Here's a question on using the Unison language.
I wanted to play around with defining APIs for data sources/sinks/feeds etc, but I hit a wall. I don't know how I should define an API in unison without tying down the underlying datatype used to implement it.
As a example, consider the following bit of Haskell.
-- let's ignore for the purposes of this discussion whether this is a wise definition of a stream...
class StreamT s where
get :: s a -> (a, s a)I could instantiate that for a type data Stream a = Cons a (Stream a) (The fact I've used laziness here is not important to the question at hand). If my code uses StreamT, then I've avoided coupling to the particular choice of datatype Stream, and I could swap it out for another one later.
How should I go about this kind of thing in Unison? Here are the two encodings I've thought of.
data StreamT s = StreamT (s a -> (a, s a))
do_stuff_1 : StreamT s -> s a -> (a ->{e} b) ->{e} ()This is typeclasses without the sugar (and handy method search/dispatch and coherence checks).
ability StreamT s where -- except probably we don't support abilities with
-- type params, let alone higher kinded ones?
get : s a ->{ StreamT s } (a, s a)
stream_handler : Effect (StreamT Stream) t -> t
do_stuff_2 : s a -> (a ->{e} b) ->{e, StreamT s} ()This is using abilities to delay binding to the specific type's methods.
Could we imagine the language supporting idris-style interfaces one day? (i.e. typeclasses without the coherence checking.)
The answer was: use the direct encoding (or the ability one if it fits); and maybe one day unison will have something similar to typeclasses (but note this).