Skip to content
Takuo Watanabe edited this page Oct 24, 2018 · 1 revision

Comparing With Elm

Both Elm and Emfrp are pure functional languages because they have the referential transparency and they are strong-typed. The crucial difference between Elm and Emfrp is whether or not its language-design follows lambda-calculus. Elm can be a subspecies of Haskell, one of the most successful pure functional languages which follows lambda-calculus. On the other hand, Emfrp is not following lambda-calculus. Lambda-calculus is so powerful and has a great potential, but it is not suitable for the use on small embedded-systems without wealth amount of memory. This is because dynamic memory-allocations and the GC for it are necessary for practical lambda-calculus and that costs high amount of memory. Emfrp throws lambda-calculus away and choices a language design which doesn't require dynamic memory-allocations.

It may seem that doing FRP with this design-choice is reckless at first glance. However, In fact, the core benefits of FRP don't depend on lambda-calculus. Expressions depending on dynamic memory-allocations such as using linked-list are not needed for essential reactive programming.

Target environments that Elm and Emfrp suppose respectively are different. Elm targets Web-browsers and Emfrp targets small embedded-systems so it is meaningless to discuss which method is better. In this page, I simply compare how to handle time-varying values in Elm and Emfrp. (Elm and Emfrp call time-varying value as Signal and Node respectively.)

Defining unstatefull Signal/Node

  • In Elm:
f x = x * 2
inputSignal = constant 1
x = lift f inputSignal
  • In Emfrp:
func f(x) = x * 2
node inputNode = 1
node x = f(inputNode)

Defining stateful Signal/Node

  • In Elm:
inputSignal = constant 1
x = foldp (\x acc -> acc + x) 0 inputSignal
  • In Emfrp:
node inputNode = 1
node init[0] x = x@last + inputNode

Defining input Signal/Node

  • In Elm, all input signals from Web-browsers are pre-defined. There is also port syntax to use arbitrary inputs written in JavaScript in Elm.
port myInput : Signal Int
myapp.ports.myInput.send(0)
  • In Emfrp, because arbitrary embedded-systems' inputs cannot be pre-defined, users must define application's inputs and write IO codes to get inputs in C-language.
module MyModule in x : Int, y : Int out o use Std
void Input(int* x, int* y) {
  *x = GP0;
  *y = GP1;
}

Defining output Signal/Node

  • In Elm, the output signal is a signal assigned to the global value named main. The type of output is limited only to only types representing GUI-object and automatically processed by the Elm's runtime system.
main = lift show x
  • In Emfrp, the output is nodes nominated in module-definition with out keyword. The type of outputs is arbitrary and users need to write IO codes to process outputs in C-language.
module MyModule in x : Int out a, b use Std

node a = x + 1
node b = x + 2
void Output(int* a, int* b) {
  GP0 = *a;
  GP1 = *b;
}

Instantiating Signal/Node from template

  • In Elm, a Signal is a semi-first-class object and can appear on a returning value or argument values of functions. Users can define functions which generate Signals with arbitrary templates.
Template: function returning signal
Instantiating: function-applying
myTemplate : Signal Int -> Int -> Signal Int
myTemplate s n = lift (+n) s
s1 = constant 1
s2 = constant 2
x = myTemplate s1 100
y = myTemplate s2 200
  • In Emfrp, a Node is not first-class. So users cannot define functions on which Node appears. Alternatively, Emfrp provides a method of modularizing a Node-tree and instantiating it.
Template: module
Instantiating: newnode-definition
# MyTemplate.mfrp
module MyTemplate in a : Int, b : Int out x : Int use Std
node x = a + b
node n1 = 1
node n2 = 2
newnode x = MyTemplate(n1, 100)
newnode y = MyTemplate(n2, 200)

Sampling the last-time value of an arbitrary Signal/Node

  • Elm cannot get the last-time value of an arbitrary Signal directly. Thus, the Elm users who want to do this are forced to do a strange hack.
x : Signal Int
x = ...
lastOfX' : Signal (Int, Int)
lastOfX' = foldp (\a state -> (snd state, a)) (0, 0) x
lastOfX = lift fst lastOfX'
sampler = lift (+1) lastOfX
  • Emfrp can get last-time value of arbitrary Node.
node init[0] x : Int = ...
node sampler = x@last + 1

Clone this wiki locally