DotArrow
is the codename for "mobile code" in the context of a Pi-calculus
to
Scala
translator. It is implemented in a very simplistic fashion, for either
Scala
or Haskell
.
It is possible for Scala
in PISC
because
of three reasons:
-
input actions allow for the received value to be applied a function before returning the actual result - so that an entire
Scala
source file passed as aString
can be updated throughscala.sys.process._
facility to one modified as follows; -
the
IO
monad in the "mobile code" allows for a sequence offlatMap
s to be chained and - if wanted - to beIO.canceled
at any point between twoflatMap
s; -
Scalameta
allows forEnumerator.Generator
s to be manipulated such thatIO.canceled
is inserted after eachflatMap
with a pattern variable with ascribed type.
Also, Serializable
(case
) class
es allow for objects of type other than basic
types to be read and written using ObjectInputStream
and ObjectOutputStream
.
Alternatively, objects can be encoded to/decoded from JSON
using the Scala
library
circe.
The bin/pi.sh
shell script has been added, respectively, two functions:
dotarrowCirce
anddotarrowCirce2
;dotarrowStream
anddotarrowStream2
.
The first is used to insert _ <- IO.canceled
cancellation points, while the second
is used to transform the Scalameta
AST
by dropping the first Enumerator.Generator
together with "its" IO.canceled.
The examples/dotarrow
folder must have two sub-folders:
./examples/dotarrow/
src/
tmp/
The Scala
source files go in the ./examples/dotarrow/
folder.
The (parent) root folder contains three files for "stream
" serialization:
../dotarrow/stream/
app.scala.in
app2.scala.in
bin.in
The first two are used in the two shell functions, dotarrowStream
, respectively,
dotarrowStream2
, while the third is copied initially as the object serialization
(temporary) binary file.
And two files for "circe
" JSON
serialization:
../dotarrow/circe/
app.scala.in
app2.scala.in
These two are used in the two shell functions, dotarrowCirce
, respectively,
dotarrowCirce2
.
!!!Warning: do not delete them!!!
The examples
folder contains a dotarrow_stream_ex0.pisc
file. It contains embedded
Scala
code that uses the scala.sys.process._
facility to execute Scala
code
as it is reduced to _ <- IO { ... }.void
; the final value 196.0
can be seen.
To "execute" the "mobile code", parse the .pisc
file:
sbt:π-Calculus2Scala> run dotarrow_stream_ex0
Choose one example from the examples/dotarrow/
folder, e.g., ex3.scala
;
then - in a shell -, cd
to examples
folder, and run:
./examples $ pio dotarrow_stream_ex0
./examples $ pi dotarrow_stream_ex0.scala -- ex3
Note how "ex3
" was passed as an argument to the main
method in dotarrow_stream_ex0.scala
.
Try the same, but using circe
:
sbt:π-Calculus2Scala> run dotarrow_circe_ex0
./examples $ pio dotarrow_circe_ex0
./examples $ pi dotarrow_circe_ex0.scala -- ex4
Or both:
sbt:π-Calculus2Scala> run dotarrow_stream_circe_ex_3_4
./examples $ pio dotarrow_stream_circe_ex_3_4
./examples $ pi dotarrow_stream_circe_ex_3_4.scala
The Scala
source files must have a strict format:
-
the main object must be
object App extends IOApp.Simple
; -
the main method must be
override def run: IO[Unit]
; -
the body of the main method must be a
for-yield
comprehension; -
variable-bound generators of the
for-yield
must bind a single variable and be ascribed the type; -
definitions of the
for-yield
must correspond tocase class
es, bind a single variable for each parameter of thecase class
, and the right hand side be a single variable that is bound - immediately preceding the definition - by a generator without an ascribed type (i.e., thecase class
); -
names of variable-bound generators must not contain whitespace; their types may;
-
the scope of pattern variables in definitions and generators is limited until the first variable-bound with ascribed type generator;
-
"
if
" guards are impossible as "withFilter
" lacks from theIO
monad; -
the last
for-yield
statement must be_ <- IO { ... }.void
; -
must not output to
scala.Console.err
; -
characters in the
Scala
source files are not supported; -
in addition, for
JSON
serialization withcirce
, the implicitEncoder
s/Decoder
s must be in the scope of the main method.
It is possible for Haskell
in PISC
because
of three reasons - two as for Scala
and third:
TemplateHaskell
allows forBindS
s to be manipulated such thatexitFailure
is inserted after eachdo
-statement with a pattern variable with type signature.
Also, values can be encoded to/decoded from JSON
using the Haskell
library
aeson.
The bin/pi.sh
shell script has been added two functions:
dotarrowAeson
anddotarrowAeson2
.
To "execute" the "mobile code", parse the .pisc
file:
sbt:π-Calculus2Scala> run dotarrow_aeson_ex0
Choose one example from the examples/dotarrow/
folder, e.g., ex1/app/Main.hs
;
then - in a shell -, cd
to examples
folder, and run:
./examples $ pio dotarrow_aeson_ex0
./examples $ pi dotarrow_aeson_ex0.scala -- ex1
Note how "ex1
" was passed as an argument to the main
method in dotarrow_aeson_ex0.scala
,
while the implied (see below) "app/Main.hs
" was omitted.
Haskell Tool Stack
must be used and the
folders (e.g., "ex1
") must have a .cabal
build file; the command line launched
by PISC
is, e.g.,
stack run -- /path/to/pisc/examples/dotarrow/tmp.../app/Main.hs
from either two dotarrow
- with "stack-cabal
" setup - sub-folders:
./dotarrow/aeson
./dotarrow/aeson2
copied to, respectively:
/path/to/pisc/examples/dotarrow/tmp.../tmp/aeson
/path/to/pisc/examples/dotarrow/tmp.../tmp/aeson2
folders.
The Haskell
source files must have a strict format:
-
the executable source file must be
app/Main.hs
with moduleMain
; -
among
import
s must be the following:import System.Exit (exitFailure) import System.IO (hPutStrLn, stderr) import Inp_gUgVwYdD8r import Out_gUgVwYdD8r
where modules
Inp_gUgVwYdD8r
andOut_gUgVwYdD8r
must not be modified; -
the main method signature
main :: IO ()
and declaration must be the last two declarations; -
the body of
main
must be ado
notation; -
do
statements that bind must pattern-match a single variable with type assertion; -
do
statements thatlet
must correspond to a unique-constructordata
type, bind a single variable for each parameter of thedata
type, and the right hand side be a single variable that is bound - immediately preceding thelet
statement - by a binding without an asserted type (i.e., thedata
type); -
the last
do
statement must bereturn ()
; -
must not output to
stderr
.
This type of "mobile code" alternatively takes the form of either
Scala
or Haskell
programming language, but is very restricted.
The bin/pi.sh
shell script has been added two functions:
dotarrowScalaToHaskell
anddotarrowHaskellToScala
.
To "execute" the "mobile code", parse the .pisc
file:
sbt:π-Calculus2Scala> run dotarrow_circe_aeson_ex0
Choose one Scala
example from the examples/dotarrow/
folder, e.g., ex5.scala
or ex6.scala
, then - in a shell -, cd
to examples
folder, and run:
./examples $ pio dotarrow_circe_aeson_ex0
./examples $ pi dotarrow_circe_aeson_ex0.scala -- ex5
Note how "ex5
" was passed as an argument to the main
method
in dotarrow_circe_aeson_ex0.scala
.
The Scala
source files must have even a stricter format:
-
no
package
statements; -
only simple arithmetic expressions (without division) of type
Int
in theIO { }
blocks; -
case class
es must not share parameter names - as these are translated intoHaskell
unique-constructordata
types with identical field labels.
Note that both Scala Cli
and Ammonite
must be installed, as well as
Stack
. Also, the
Perl
script bin/Scalameta2Haskell.pl
must be available in the PATH
.
Codec
s is the codename for encoding "programs" as numeric expressions:
-
in
Scala
via providing animplicit
object
extending theNumeric
trait; -
in
Haskell
via providing aninstance
of theNum
class.
There are currently two implementation of codecs:
-
lists of integers that can be added, negated or subtracted; the multiplication operator is used to concatenate lists, e.g.,
./examples $ pi dotarrow_codec_list_aeson_ex0.scala -- ex3 ./examples $ pi dotarrow_codec_list_circe_ex0.scala -- ex11
-
an expression
DSL
that mirrors the native numeric expressions, e.g.,./examples $ pi dotarrow_codec_idem_aeson_ex0.scala -- ex4 ./examples $ pi dotarrow_codec_idem_circe_ex0.scala -- ex12
In the latter DSL
case, for example, the integers - either variables
of type Int
that have been previously bound, or literals - are wrapped
within fromInt
in an "invisible" step before the main program is run,
and the numeric operations are actually performed with DSL
values.
Because the number of examples is growing rapidly, this is the list of the commands with which they were tested as arguments:
-
Scala
./examples $ pi dotarrow_circe_ex0.scala -- ex1 ./examples $ pi dotarrow_circe_ex0.scala -- ex2 ./examples $ pi dotarrow_stream_ex0.scala -- ex3 ./examples $ pi dotarrow_circe_ex0.scala -- ex4 ./examples $ pi dotarrow_codec_list_circe_ex0.scala -- ex11 ./examples $ pi dotarrow_codec_idem_circe_ex0.scala -- ex12 ./examples $ pi dotarrow_codec_idem_circe_ex0.scala -- ex13
-
Haskell
./examples $ pi dotarrow_aeson_ex0.scala -- ex1 ./examples $ pi dotarrow_aeson_ex0.scala -- ex2 ./examples $ pi dotarrow_codec_list_aeson_ex0.scala -- ex3 ./examples $ pi dotarrow_codec_idem_aeson_ex0.scala -- ex4 ./examples $ pi dotarrow_codec_idem_aeson_ex0.scala -- ex5
-
Scala
&Haskell
./examples $ pi dotarrow_circe_aeson_ex0.scala -- ex5 ./examples $ pi dotarrow_circe_aeson_ex0.scala -- ex6 ./examples $ pi dotarrow_circe_aeson_ex0.scala -- ex7 ./examples $ pi dotarrow_circe_aeson_ex0.scala -- ex8 ./examples $ pi dotarrow_circe_aeson_ex0.scala -- ex9 ./examples $ pi dotarrow_circe_aeson_ex0.scala -- ex10