I read article about generic programming in PureScript and a typical generic function requires to define a dedicated type-class (e.g. Show) and provide instances for all types which could appear as arguments of generic data constructors.
Is there a short cut to avoid such hassle when a generic function is interested in a particular type and a value of any other type is mapped with identity function?
Sure, I have a set of record types with type parameter f.
data ExprT f
= Filter (FilterBodyT f)
| Or (Array (f (ExprT f)))
type FilterBodyT f =
{ predicate :: f (PredicateT f)
, trainedOn :: Array ChartId
}
The type variable f could be Maybe or Identity. Maybe is used in form state to represent partial value in a structured editor.
Server version of these types doesn’t have f - it i assumed that Identity is applied, so on PureScript side should be a function traversing such tree and replacing all Justs to pures.
Example with Show is natural, because every value is showed, but here non generic values are left intact and defining empty instances seems boring job.
Is there Data in PureScript? I haven’t found such thing.
My motivation is simple - I started writing PureScript after Haskell and my subconscious assumption that every problem X in PureScript is easier or as hard as in Haskell. PureScript is positioned as Haskell on frontend and talking about Haskell everybody think about type acrobatics first.
No, the is no Data in PureScript. But nothing is stopping you from making it. Declare the class, give it a gmapT method, make instances for all the types you need - and there you go, you can do everything you can do in Haskell.
The one difference would be that in Haskell you wouldn’t have to make instances for all the types manually, the compiler can do it for you. Which is why I’m asking: is that the bit you’re looking for? Or are you ok with defining instances yourself?
May I recommend a different, equivalent (at least on this example) approach?
Instead of parametrizing on f :: Type -> Type, where the two instances of f are Maybe and Identity, consider parametrizing on i :: Type (for ‘incomplete’), where the two instances of i are Unit and Void.
Replace all applications of f in your types with Either i:
data ExprT i
= Filter (FilterBodyT i)
| Or (Array (Either i (ExprT i)))
type FilterBodyT i =
{ predicate :: Either i (PredicateT i)
, trainedOn :: Array ChartId
}
Now derive Functor, Foldable, and Traversable for ExprT and PredicateT.
Assuming you can do the above, your desired finishDesign is:
Yes, Haskell and PureScript allow a fair amount of type acrobatics, but you can often get farther by not trying to jump quite so high.
(If you are troubled by all the Rights that a serialization of an ExprT Void would contain, there’s no need to use literal Either for this; you could wrap it in a newtype with custom serialization rules.)
There must be a reason, if nobody defined Data class before I discovered that fact.
In the ideal world I would get PureScript record types via translation of Haskell ones, but I haven’t get to such skill state yet.
Is there a Haskell solution for translating types to PureScript which can generate Data instances for PureScript as a bonus?
Purescript doesn’t have Data because it doesn’t have Typeable. Typeable in Haskell has its instances automatically derived by the compiler, but the PureScript compiler doesn’t have that feature yet. However you can work around that limitation with various caveats.
The caveat of my approach is that I depend on how the compiler does dictionary passing at runtime. But the benefit is that you don’t have to write Typeable instances yourself (apart from a very straightforward TagT instance which the compiler will prevent you from getting wrong). You can read the usage notes here - GitHub - ajnsit/purescript-typeable: Reified types for Purescript.
I have changed the representation of Typeable to not depend on the internal dictionary passing mechanism. There is still a dependence on PureScript using stable dictionaries at runtime (which seems a much stronger guarantee), but the situation is now much better than earlier.