I tried to use extensible records, to call the same function (funcOnBase) on multiple subtypes. This is my code:
import Html exposing (text)
type alias Base a = { a | foo : Int }
type alias Sub1 = Base { bar : String }
type alias Sub2 = Base { baz : Float }
type SubTree = S1 Sub1 | S2 Sub2
funcOnBase : Base a -> Bool
funcOnBase b = b.foo > 0
funcOnSTree : (Base a -> Bool) -> SubTree -> Bool
funcOnSTree fnc x =
case x of
S1 s1 -> fnc s1
S2 s2 -> fnc s2
main =
text (Debug.toString <| funcOnSTree funcOnBase <| S1 { foo = -5, bar = "" })
Unfortunately I get this error:
The 1st argument to `fnc` is not what I expect:
16| S1 s1 -> fnc s1
^^
This `s1` value is a:
Sub1
But `fnc` needs the 1st argument to be:
{ a | foo : Int }
Hint: Seems like a record field typo. Maybe bar should be foo?
Hint: Can more type annotations be added? Type annotations always help me give
more specific messages, and I think they could help a lot in this case!
The s1 value is a Sub1, which is Base { bar : String } = { foo : Int, bar : String }. Why is it not accepted as { a | foo : Int }?
Ok, so type parameter in function definition must be used in a way that when instantiation is done,
the resulting fixed type agrees across all uses? (Or something like that, I’m not sure how to say this correctly.)
For example following works because when type parameters a and b are instantiated, they will be same types both in fncA/fncB and in GenericSubTree?
type alias Base a = { a | foo : Int }
type alias Sub1 = Base { bar : String }
type alias Sub2 = Base { baz : Float }
type GenericSubTree x y = S1 (Base x) | S2 (Base y)
type alias SubTree = GenericSubTree Sub1 Sub2
funcOnBase : Base a -> Bool
funcOnBase b = b.foo > 0
funcOnSTree : (Base a -> Bool) -> (Base b -> Bool) -> GenericSubTree a b -> Bool
funcOnSTree fncA fncB x =
case x of
S1 s1 -> fncA s1
S2 s2 -> fncB s2
Other FP languages support type classes, but in Elm I can not fix it that way.
I would like to write a generic map for the type SubTree wich works on Base, so putting the funcOnBase inside the 'let` block is not an option:
mapTreeBase : (Base a -> b) -> SubTree -> b
mapTreeBase fnc x =
case x of
S1 s1 -> fnc s1
S2 s2 -> fnc s2
Could you please give some more details about how to use this Forall notation? I was not able to find anything about it.
If I put foral or Forall in the code, I get syntax error.
Thank you for the suggestion, but not really. That function is far from generic. Your funcOnSTree implementation requires fncAfncB instead of a single fnc parameter.
In this simplified example I have only two subtypes, but I would like to create a mapTreeBase with 7 of them.