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)