I have a typeclass that looks like this:
module Observation where
import Prelude
import Prelude qualified as P ((+))
class Observation f a where
konst : a -> f a
(+) : f a -> f a -> f a
(===): f a -> f a -> f Bool
This generates an expression tree, which I would like to be able to serialize to the ledger. I can use it to write expression such as:
(kons 1 + kons 2) === konst 3
To achieve this, I’ve taken the approach similar to that described in Functions - Can we pass them as arguments in a choice? , of encoding it as a data type Obs:
instance Observation Obs a where
konst = Const
(+) = Add
(===) = Equals -- FAILS TO COMPILE
data Obs a
= Const a
| Add with lhs: Obs a, rhs: Obs a
| Equals with lhs: Obs a, rhs: Obs a
Now this doesn’t work - error on the implementation of (===) = Equals. The reason is that in the typeclass, this requires a return type of Obs Bool, but the ADT constructor Equals infers an Obs a.
This is practically the motivating problem described for GADTs in the Haskell wiki. This language feature doesn’t quite work in DAML unfortunately.
@cocreature Also suggested I look at using a different encoding using the Yoneda lemma. An example is given in this blog post, about half way down the page. But you’ll notice the transformation embeds a function into the ADT, which is not serializable, so that doesn’t help.
I also considered splitting up the algebra in two, with boolean algebra looking something like this:
data Boolean
= Equals : forall a . (Obs a, Obs a)
...
You’ll notice this data type doesn’t have a type parameter a so it’s not inferred. But this also requires a language feature that isn’t supported.
Finally, I should mention that there are a couple of not-so-great solutions, such as ‘tagging’ the type a, by using e.g. Either a Bool instead. This has the major disadvantage that writing expressions will no longer warn of type errors at compile-time. For example, the expression
Left 1 === Right false
would compile fine (although it would throw an error at runtime).
I’m fresh out of ideas. Could anybody suggest an alternative approach?