purescript-contrib / purescript-matryoshka

Generalized folds, unfolds, and traversals for fixed point data structures
Apache License 2.0
59 stars 13 forks source link

Failed attempt to port example #3

Closed rintcius closed 7 years ago

rintcius commented 7 years ago

I am trying to port the example from https://github.com/slamdata/matryoshka/blob/master/README.md and a simplified form works (prematurely choosing Mu ExprF), but I can't get the generalized version working.

module Main where

import Prelude

import Control.Monad.Eff.Console

import Data.Functor.Mu
import Matryoshka

data ExprF a = Num Int | Mul a a

derive instance functorExprF :: Functor ExprF

eval :: Algebra ExprF Int
eval (Num i) = i
eval (Mul i j) = i * j

-- Another (smaller) issue I encountered, uncommenting this type doesn't compile
-- It gives "Could not match type Mu with type ExprF" in the main function
--evalExpr :: forall a. Recursive (ExprF a) ExprF => ExprF a -> Int
evalExpr = cata eval

type Expr = Mu ExprF

num :: Int -> Expr
num i = embed (Num i)

mul :: Expr -> Expr -> Expr
mul i j = embed (Mul i j)

someExpr :: Expr
someExpr = mul (num 2) (mul (num 3) (num 4))

main = do
  -- this works ok
  logShow $ evalExpr someExpr

-- attempt to generalize fails..
-- the code below compiles, but then I can't instantiate it using `Mu`
num' :: forall a. Corecursive (ExprF a) ExprF => Int -> ExprF a
num' i = embed (Num i)

mul' :: forall a. Corecursive (ExprF a) ExprF => ExprF a -> ExprF a -> ExprF a
mul' i j = embed (Mul i j)

someExpr' :: forall a. Corecursive (ExprF a) ExprF => ExprF a
someExpr' = mul' (num' 2) (mul' (num' 3) (num' 4))

Got an idea what I am missing?

garyb commented 7 years ago

It's the constraints you're using - they're overly specific. For Recursive and Corecursive the first parameter should be left as polymorphic, as essentially that's "where the Mu goes":

module Main where

import Prelude

import Control.Monad.Eff.Console

import Data.Functor.Mu
import Matryoshka

data ExprF a = Num Int | Mul a a

derive instance functorExprF :: Functor ExprF

type Expr = Mu ExprF

eval :: Algebra ExprF Int
eval (Num i) = i
eval (Mul i j) = i * j

evalExpr :: forall t. (Recursive t ExprF) => t -> Int
evalExpr = cata eval

num :: forall t. Corecursive t ExprF => Int -> t
num i = embed (Num i)

mul :: forall t. Corecursive t ExprF => t -> t -> t
mul i j = embed (Mul i j)

someExpr :: forall t. Corecursive t ExprF => t
someExpr = mul (num 2) (mul (num 3) (num 4))

main = do
  logShow $ evalExpr (someExpr :: Expr)

This library really needs some documentation, but it's a pretty monumental task! I want to do a good job with that, but I've not had time to get started on it yet, with the other projects I have on the go at the moment.

rintcius commented 7 years ago

Great, thanks a lot!

I can understand about the documentation part. No problem (also I like fiddling with this - a good way to learn I think)!

If you like, I'm also happy to add documentation (e.g. starting with some documentation around this code) - but then again I can also understand if you prefer to do it yourself, as it would be mainly a learning experience for me.

garyb commented 7 years ago

Please do :). Adding example files like this would be welcome too.

rintcius commented 7 years ago

Ok great, will do!