Using Elm for science

Find this presentation at:

http://slides.com/danielbachler/elm-for-science

Douglas Connect

Some background

  • 16 people, fully remote consulting company
  • Focused on toxicology, cheminformatics
  • Try to improve data management & machine learning → less animal testing
  • Only 4 software engineers

Constraints & Goals

  • Efficient use of engineers time
  • Create apps that work well & don't break
  • Performance is usually no big concern
  • Code should be easy to extend or customize

Motivations to use Elm

  • Javascript is crazy
  • Elm often takes a little longer in the beginning, but is more time efficient in the long run
  • Refactorings are fun & improve products
  • Type system makes many tests obsolete

Showcase

ITS

Build setup

  • Brunch to compile & bundle
  • Cactus for static page templates
  • Nginx in alpine docker container
  • Deployed to Kubernetes cluster

Notes

Third party molecule drawing widget

Animated tooltips (Bootstrap)

Design workflow (html-to-elm)

Parsing numbers

type NumberParseError
    = Empty
    | InvalidCharacters
    | OutOfRange

type alias NumericField numberType =
    { textContent : String
    , parseResult : Result NumberParseError numberType
    }


type alias FloatField =
    NumericField Float


type alias IntField =
    NumericField Int

Showcase:
Data Explorer

Swagger example

type: object
properties:
  name:
    type: string
  age:
    type: integer
type SimpleDataType
    = TypeInteger
    | TypeFloat
    | TypeString
    | TypeBoolean

type alias ObjectField =
    { fieldname : String
    , content : DataType
    }

type DataType
    = TypeSimple SimpleDataType
    | TypeObject (List (ObjectField))

Dealing with $refs

type: object
properties:
  name:
    type: string
  address:
    $ref: '#/definitions/Address'
  age:
    type: integer

Handling $Refs - attempt #1

type SimpleDataType
    = TypeInteger
    | TypeFloat
    | TypeString
    | TypeBoolean

type alias ObjectField =
    { fieldname : String
    , content : DataType
    }

type DataType
    = TypeSimple SimpleDataType
    | TypeObject (List (ObjectField))
    | Ref String

Annoying to consume (dereference at every usage)

Handling $Refs - attempt #2

type alias ObjectFieldWithRef =
    { fieldname : String
    , content : DataTypeWithRef
    }

type DataTypeWithRef
    = TypeSimpleWithRef SimpleDataType
    | TypeObjectWithRef (List (ObjectField))
    | Ref String

type alias ObjectFieldWithoutRef =
    { fieldname : String
    , content : DataTypeWithoutRef
    }

type DataTypeWithoutRef
    = TypeSimpleWithoutRef SimpleDataType
    | TypeObjectWithoutRef (List (ObjectField))

Handling $Refs - attempt #3

type alias ObjectField referencekind =
    { fieldname : String
    , content : referencekind 
    }

type DataType referencekind 
    = TypeSimple SimpleDataType
    | TypeObject (List (ObjectField referencekind ))

type DataTypeOrRef
    = Reference String
    | SpecifiedDataType DataType    

type DataTypeValOnly
    = DataTypeValOnly DataType

deref : DataType DataTypeOrRef -> DataType DataTypeValOnly
deref dataTypeWithRefs =
    -- ...

Building Json decoders

type Cell
    = IntCell Int
    | FloatCell Float
    | StringCell String

buildJsonDecoder : DataType DataTypeValOnly
                    -> Decode.Decoder (List Cell)
buildJsonDecoder dataTypeNode =
  case dataTypeNode  of
     TypeSimple simpleType ->
       case simpleType of
         TypeInteger ->                    
           Decode.map (List.singleton << IntCell) Decode.int

          -- ...
     TypeObject fieldDefinitions ->
       -- fold over list of fields and accumulate
       -- decoders of lists of cells and concat them

Wishlist

Newtypes

Restricting type variables

newtype Ref = String

type alias RefDict = Dict Ref String

Thank you!

Find me on Twitter: @danyx23

This presentation is available at:

http://slides.com/danielbachler/elm-for-science

elm-for-science

By Daniel Bachler

elm-for-science

  • 1,522