I’m playing with PureScript this morning, to understand more about Monads.

Given this implementation:

mul :: forall m n. Bind m => Applicative m => Semiring n => m n -> m n -> m n
mul ma mb = do
a <- ma
b <- mb
pure (a * b)

I can make these tests pass:

-- ...
assert $
Just 12 ==
mul (Just 3) (Just 4)
assert $
Nothing ==
mul Nothing (Just 4)
assert $
Nothing ==
mul (Just 3) Nothing

However, introducing Either requires me to implement Eq

assert $
Right 12 ==
mul (Right 3) (Right 4)

I did find a reference for this requirement in the Data.Either docs:

(Eq a) => Eq1 (Either a)
(Ord a, Ord b) => Ord (Either a b)
The Ord instance allows Either values to be compared with compare, >, >=, < and <= whenever there is an Ord instance for both types the Either can contain.
Any Left value is considered to be less than a Right value.

But I can’t quite understand how I should implement this. My hunch is that I need to tweak the type signature but I’m not sure.

Hi - the issue is with the tests - those need the instance to be Eq and indeed I think the problemis not the code you wrote (this should be Eq, including Right 3) but that the Left type of your Either will not be known (and thus infered as some type-variable a) and thus the typechecker will complain - you should be able to help out like this: assert $ (Right 12 :: Either String Int) == mul (Right 3) (Right 4) (basically: give the typechecker a hint)

disclaimer: I did not try this out so chances are that I typed some syntax/type error - sorry

you don’t have to “commit” to the type but you have to make sure that it is Eq - and I think Show but I could be wrong here)

So there needs to be a forall a. Eq a => Show a => Either a Int and to be honest: I’m not sure if you can plug this in there (I’m not sure if this is allowed syntax) - I think you could do this with a let or where:

assert $ expected ...
where
expected :: forall a. Eq a => Show a => Either a Int
expected = Right 12

ok - I guess Purescript does not fall back to defaults then (the actual code you gonna run needs actual types as the type-class instances are passed via a dictionary - I somehow thought Purescript would use default types - when I think about it it’s probably a rather stupid assumption - sorry)

Yeah, Haskell has a defaulting mechanism that we decided not to implement way back in the mists of time. Although it would have been nice in this case, it can also be confusing as it’s very ad-hoc. It’s even worse when you’re in GHCi, as it adds a bunch of extra defaults than then don’t work in real code.

yes that was what I was thinking about - in the end it’s not really a loss IMHO - defaults + monomorphism-restriction while nice can be a huge “WTF” generator in Haskell