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:
elm-for-science
By Daniel Bachler
elm-for-science
- 1,522