0

how do i define a monad for such a datatype in Haskell? It is basically a salsa interpreter. And I cant figure out what should the return look like. It is making me crazy...

newtype Salsa a = Salsa { runSalsa :: Context -> Either String (a, Context, Animation)} instance Monad Salsa where return a = Salsa $ .......... instance Functor Salsa where fmap = liftM instance Applicative Salsa where pure = return (<*>) = ap 

http://ap-e2015.onlineta.org/assignments/assignment-1-salsa-interpreter.html

1
  • 2
    What is salsa? It would be helpful to provide a link. Commented Sep 11, 2015 at 19:02

3 Answers 3

6

You need a function which takes a Context so use a lambda \con ->.

You don't have anything that has failed so far so you can always succeed. Right.

a is provided by the call to return. (a,.

Context is provided by the call to the lambda. con,.

Now you have to decide on the animations to include, I would guess none. []). (Note I don't remember offhand the exact syntax there but I think this is right).

Putting it all together you get:

return a = Salsa $ \con -> Right (a, con, []) 

Now comes the complicated case where you have to handle bind (>>=).

Sign up to request clarification or add additional context in comments.

3 Comments

I did this: instance Monad Salsa where return a = Salsa $ \con -> (a, con, [] :: Animation) but it says that Couldn't match expected type Either String (a, Context, Animation)' with actual type (a, Context, Animation)' Relevant bindings include a :: a (bound at SalsaInterp.hs:33:12) return :: a -> Salsa a (bound at SalsaInterp.hs:33:5) In the expression: (a, con, [] :: Animation) In the second argument of ($)', namely \ con -> (a, con, [] :: Animation)' In the expression:.....
How can I show what to do in Left case and what in Right?
@Ezis All that is missing (for return, at least) is wrapping the tuple in Right.
3

Help yourself with typed holes: Write an underscore where you are stuck:

instance Monad Salsa where return a = Salsa $ _ 

and the compiler tells you it needs a function here

Found hole ‘_’ with type: Context -> Either String (a, Context, Animation) 

Now you can work your way with

instance Monad Salsa where return a = Salsa $ \x -> _ 

For >>=, do almost the same:

(Salsa s) >>= f = Salsa $ \x -> _ 

and the compiler outputs

Found hole ‘_’ with type: Either String (b, Context, Animation) Relevant bindings include con :: Context f :: a -> Salsa b s :: Context -> Either String (a, Context, Animation) 

So, s is function that requires a Context, but our con supplies one, put it together:

(Salsa s) >>= f = Salsa $ \con -> let s' = s con in _ ... s' :: Either String (a, Context, Animation) (bound at Review.hs:12:43) f :: a -> Salsa b (bound at Review.hs:12:19) 

So we need that a thing out of s' to supply it to f. Pattern match on s' (while renaming):

(Salsa salsaFunction1) >>= f = Salsa $ \context1 -> let salsaResult1 = salsaFunction1 context1 in case salsaResult1 of Left errorMsg -> Left errorMsg Right (a, context2, animation1) -> let Salsa salsaFunction2 = f a salsaResult2 = salsaFunction2 context2 in _ salsaFunction2 :: Context -> Either String (b, Context, Animation) animation1 :: Animation context2 :: Context a :: a salsaResult1 :: Either String (a, Context, Animation) context1 :: Context f :: a -> Salsa b salsaFunction1 :: Context -> Either String (a, Context, Animation) 

So, we have another salsaFunction2, and an unused context2. You already saw how to put this together: do another case analysis, in the Right case supply context3, the monadic result b and combine both animations to provide the final Either String (b, Context, Animation) that was seen again and again:

Found hole ‘_’ with type: Either String (b, Context, Animation) 

5 Comments

instance Monad Salsa where return a = Salsa $ \con -> Right (a, con, [] :: Animation) (Salsa function) >>= f = Salsa $ \con1 -> let result = function con1 in case result of Left errorMsg -> Left errorMsg Right (a, con2, anim) -> let Salsa function2 = f a result2 = function2 con2 in case result2 of Left errorMsg -> Left errorMsg anim3 = anim ++ anim2 Right (b, con3, anim2) -> Right (b,con3, anim3)
Could you elaborate on that? I think i am close
instance Monad Salsa where return a = Salsa $ \con -> Right (a, con, [] :: Animation) (Salsa function) >>= f = Salsa $ \con1 -> let result = function con1 in case result of Left errorMsg -> Left errorMsg Right (a, con2, anim) -> let Salsa function2 = f a result2 = function2 con2 in case result2 of Left errorMsg -> Left errorMsg Right (b, con3, anim2) -> Right (b,con3, mappend anim anim2)
That newest one compiles. How can i make sure that it is correct?
The magic of haskell is: when it compiles, it usually is right. From what I see your solution looks good.
1

Well, I don't know anything about Salsa, but after reading Guvante's answer foreshadowing the difficulty of implementing >>=, I thought it would be an interesting exercise. And since I don't know what Salsa's Context or Animation types are, I decided to just parameterize over them, which I think worked out fairly well: the type of Context can be totally opaque to us as implementors of >>=, and we just need Animation to be a monoid:

newtype Salsa ctx error anim a = Salsa { runSalsa :: ctx -> Either error (a, ctx, anim) } instance Monoid anim => Monad (Salsa ctx error anim) where return x = Salsa $ \ctx -> return (x, ctx, mempty) (Salsa m) >>= f = Salsa m' where m' ctx = m ctx >>= handle handle (x, ctx, anims) = let (Salsa f') = f x merge (a, b, c) = (a, b, mappend anims c) in merge <$> f' ctx instance Monoid anim => Functor (Salsa ctx error anim) where fmap = liftM instance Monoid anim => Applicative (Salsa ctx error anim) where pure = return (<*>) = ap 

This as general as I could figure how to make it, and I'm still not totally happy with the implementation of handle: it seems like there must be a better way to get the animation results combined than letting a function and then fmapping it, but I couldn't find anything prettier.

Incidentally I think it would be nicer to have a real data type for this (a, Context, Animation) group rather than just a tuple. Then you could, for example, give it a Functor instance and simplify the implementation of handle, removing the merge function and just writing

mappend anims <$> f' ctx 

2 Comments

I don't think your implementation is ugly. At heart, this is State + Writer + Either, so it is not surprising that the plumbing gets a bit hairy.
I believe when @Guvante wrote "Now comes the complicated case" for >>= they were omitting the >>= part on purpose, so not to hand out the full solution to the assignment and make the OP work on it on their own.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.