Search code examples
javascripttreefunctorelmalgebraic-data-types

How do the native JavaScript types get written in Elm?


How do the native JavaScript types get written in Elm? The files defining List are surprisingly short and easy to read:

I am curious of how Elm does it's job of proving a type-safe interface to JavaScript. Is the JavaScript written by hand, or is it compiled from another language like Haskell?


Elm's List Type

The key line of Elm seems to be ...

module List exposing
  ( isEmpty, length, reverse, member
  , head, tail, filter, take, drop
  , repeat, (::), append, concat
  )

import Basics exposing (..)
import Maybe
import Maybe exposing ( Maybe(Just,Nothing) )
import Native.List

(::) : a -> List a -> List a
(::) = Native.List.cons

infixr 5 ::

head : List a -> Maybe a
head list =
  case list of
    x :: xs ->
      Just x

    [] ->
      Nothing

tail : List a -> Maybe (List a)
tail list =
  case list of
    x :: xs ->
      Just xs

    [] ->
      Nothing

This tells us that head and tail can be defined within Elm, but (::) operation must be defined with JavaScript. Here are some key lines in JavaScript to have to do with the constructor:

var _elm_lang$core$Native_List = function() {

var Nil = { ctor: '[]' };

function Cons(hd, tl) { return { ctor: '::', _0: hd, _1: tl }; }

...

return {
    Nil: Nil,
    Cons: Cons,

    // etc
};

}();

I am especially curious about the line { ctor: '::', _0: hd, _1: tl }; since the word ctor is the second half of the word functor -- which may mean a functor was written in JavaScript.


These considerations are important because I am considering writing a Tree a and/or QuadTree a type and it might be good to write from inside Elm (e.g. using Records) or to write a module for personal use.

  • one implementation of tree could just have nodes
  • another could distinguish between Left and Right nodes
  • another just has 4 indistinguishable nodes.

Another example could be CircularList but I just want to focus on trees for now.


Solution

  • My hunch is that the implementation of List is written in Javascript primarily because its constructors are [] and ::, but Elm doesn't allow for infix operators as constructor names.

    For example, the way we use List in Elm means the definition really should be something like this:

    type List a = ([]) | (::) a (List a)
    

    That doesn't compile in Elm even though we pattern match on those constructors, so the shortcut of using Javascript to define the implementation is used.

    If you write your own custom list implementation with different names, the javascript output is the same as the javascript implementation of List.

    type MyList a = MyNil | MyCons a (MyList a)
    

    ... yields ...

    var _user$project$Temp1467112617033056$MyCons = F2(
      function (a, b) {
        return {ctor: 'MyCons', _0: a, _1: b};
      });
    var _user$project$Temp1467112617033056$MyNil = {ctor: 'MyNil'};
    

    Therefore, I don't see any reason why your proposed Tree or QuadTree types would benefit from being written in a Native javascript module. I'd recommend writing them in Elm.