That looks cool!
I threw together something that just covered my initial use case; the parts I can share are here.
It’s not as complete as what you have shared but the part I spent most time on was the Expression
s.
I took the approach of having an underlying untyped AST (here) and a second type which wraps it and uses a phantom type to give a degree of type safety when constructing expressions (here).
For example, the exposed case_
function ensures all branches and the default are of the same type and each case test is of type Bool
:
case_ : List ( Expression Bool, Expression a ) -> Expression a -> Expression a
case_ cases (E default) =
let
cs =
List.map (\( E b, E a ) -> ( b, a )) cases
in
E <| Case cs default
Feel free to grab it if you think it’s useful
The code below is the example for a heatmap layer from the Mapbox docs.
Note that each of the heatmaps properties is also typed, e.g.
heatmapColor : Expression Color -> Heatmap -> Heatmap
heatmapOpacity : Expression Float -> Heatmap -> Heatmap
...
The expression is then:
import Mapbox.GL.Expression as Expr
import Mapbox.GL.Layer.Heatmap as Heatmap
import Mapbox.GL.Layer as Layer
import Mapbox.GL.Source as Source
heatmapLayer =
Heatmap.heatmap "earthquakes-heat" (Source.reference "earthquakes")
|> Heatmap.heatmapWeight
(Expr.interpolate
Expr.linear
(Expr.get_ "mag")
[ ( Expr.number 0, Expr.number 0 )
, ( Expr.number 6, Expr.number 1 )
]
)
|> Heatmap.heatmapIntensity
(Expr.interpolate
Expr.linear
Expr.zoom
[ ( Expr.number 0, Expr.number 0 )
, ( Expr.number 9, Expr.number 3 )
]
)
|> Heatmap.heatmapColor
(Expr.interpolate
Expr.linear
Expr.heatmapDensity
[ ( Expr.number 0, Expr.color (Color.rgba 33 102 172 0) )
, ( Expr.number 0.2, Expr.color (Color.rgb 103 168 207) )
, ( Expr.number 0.4, Expr.color (Color.rgb 209 229 240) )
, ( Expr.number 0.6, Expr.color (Color.rgb 253 219 199) )
, ( Expr.number 0.8, Expr.color (Color.rgb 239 138 98) )
, ( Expr.number 1.0, Expr.color (Color.rgb 178 24 43) )
]
)
|> Heatmap.heatmapRadius
(Expr.interpolate
Expr.linear
Expr.zoom
[ ( Expr.number 0, Expr.number 2 )
, ( Expr.number 9, Expr.number 20 )
]
)
|> Heatmap.heatmapOpacity
(Expr.interpolate
Expr.linear
Expr.zoom
[ ( Expr.number 7, Expr.number 1 )
, ( Expr.number 9, Expr.number 0 )
]
)
|> Layer.heatmap