Reputation:
I'm not sure this is possible. I have something like the following class:
data Bar a = Bar1 a | Bar2
class Foo f where
foo :: f a -> Either [String] a
instance Foo Bar where
foo (Bar1 x) = Right x
foo Bar2 = Left ["is Bar2"]
Now I want to be able to define an instance that given an implementation for Foo f
implement Foo [f]
.
So something like this:
data Bar a = Bar1 a | Bar2
class Foo f where
foo :: f a -> Either [String] a
instance Foo Bar where
foo (Bar1 x) = Right x
foo Bar2 = Left ["is Bar2"]
instance Foo f => Foo [f] where
foo as = foldr reducer (Right []) (foo <$> as)
where
reducer (Right n) (Right xs) = Right $ n:xs
reducer (Left xs) (Right _) = Left xs
reducer (Right _) (Left xs) = Left xs
reducer (Left xs) (Left ys) = Left $ xs ++ ys
Where the list instance just accumulates all lefts and if there no lefts it removes the outer list and moves it to the right (can this be written implemented easier?). The instance like this doesn't type check since the type isn't [f] a
but [f a]
. The type I expect is foo :: [f a] -> Either [String] [a]
I tried to write a type that this does for me:
type ApplyList (f :: Type -> Type) (a :: Type) = [f a]
instance Foo f => Foo (ApplyList f) where
...
But this doesn't work because I guess types do not support currying.
Is there a way to write this correctly?
Any help is appreciated!
Upvotes: 0
Views: 90
Reputation:
I ended up changing my class to have the fully applied input and output type. It's a little bit clunky but it works.
class Foo f g where
foo :: f -> Either [String] g
instance Foo (Bar a) a where
foo (Bar1 x) = Right x
foo Bar2 = Left ["is Bar2"]
instance Foo f g => Foo [f] [g] where
foo as = foldr reducer (Right []) (foo <$> as)
where
reducer (Right n) (Right xs) = Right $ n:xs
reducer (Left xs) (Right _) = Left xs
reducer (Right _) (Left xs) = Left xs
reducer (Left xs) (Left ys) = Left $ xs ++ ys
Upvotes: 2