Hello,
For the last couple of days I have tried to implement type level String check at compile time but it seems I cannot figure this out. Maybe what I try to achieve doesn’t make sense and I would love someone to clarify this for me.
Let’s say I have a data structure like so :
data Node (shape :: Symbol) = Node { id :: String, shape :: String }
Now I want to do operations on such nodes but only if they are of the same shape, so I have a function like the following which is trivial for simplicity sake :
doOnSameShape :: forall s. IsSymbol s => Node s -> Node s -> Effect Unit
doOnSameShape _ _ = let shape = reflectSymbol (SProxy :: SProxy s) in log $ "Shape is : " <> shape
All good so far, except I can lie to the compiler and “fake” the shape of a Node, for example this would compile fine :
doOnSameShape (Node { id : "x", shape : "circle" } :: Node "circle") (Node { id : "y", shape : "square" } :: Node "circle")
It compiles fine but we annotated the type of the second Node with “circle” whereas it is a “square”
And here is the problem, how can I make sure that Node are constructed with the right type depending on the shape field value ? I tried multiple things but none of them worked, my latest try is the following :
cons :: forall s. IsSymbol s => String -> String -> Node s
cons id shape = reifySymbol shape $ reifyNode (SProxy :: SProxy shape) id
reifyNode :: forall s1 s2. IsSymbol s1 => IsSymbol s2 => Compare s1 s2 EQ => SProxy s1 -> String -> SProxy s2 -> Node s1
reifyNode s id _ = Node { id : id, shape : reflectSymbol s }
With this I had hoped I could just do :
doOnSameShape (cons "x" "square") (cons "y" "square")
And the compiler would figure out the type of both cons calls, but I got very disappointed when the compiler threw the following error in the cons function at reifyNode call :
No type class instance found for
Prim.Symbol.Compare s2
sym3
EQ
I really don’t get what I need to do, if ever there is something to do to fix it at this point. Is it because of the signature of reifySymbol being :
reifySymbol :: String -> (forall sym. IsSymbol sym => SProxy sym -> r) -> r
Hence I will never be able to compare sym and my s Symbols ?
Many thanks in advance for your help