One of the nice things about Haskell is the ability to use infix notation.开发者_运维知识库
1 : 2 : 3 : [] :: Num a => [a]
2 + 4 * 3 + 5 :: Num a => a
But this power is suddenly and sadly lost when the operator needs to be lifted.
liftM2 (*) (liftM2 (+) m2 m4) (liftM2 (+) m3 m5)
liftM2 (:) m1 (liftM2 (:) m2 (liftM2 (:) m3 mE))
It is possible to define similar operators in order to regain this power
(.*) = liftM2 (*)
(.+) = liftM2 (+)
(.:) = liftM2 (:)
m1, m2, m3, m4, m5 :: Monad m, Num a => m a
mE = return [] :: Monad m => m [a]
m1 .: m2 .: m3 .: mE :: Monad m, Num a => m [a]
m2 .+ m4 .* m3 .+ m5 :: Monad m, Num a => m a
But it is tedious to need to rename every operator I want to use in a monadic context. Is there a better way? Template Haskell, perhaps?
You can make all monads instances of Num
:
{-# LANGUAGE FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
import Control.Monad
instance (Monad m, Num n, Show (m n), Eq (m n)) => Num (m n) where
(+) = liftM2 (+)
(*) = liftM2 (*)
Then you can do f.e.:
*Main> [3,4] * [5,6] + [1,2]
[16,17,19,20,21,22,25,26]
But this only works for operators that are defined with type classes. With :
this isn't possible.
You can define a new infix lift:
v <. f = liftM2 f v
f .> v = f v
Example use:
[3] <.(+).> [4]
...but I don't know of any real way that isn't 100% annoying.
There is the style using ap
:
return (:) `ap` Just 1 `ap` Just []
or applicative style:
(:) <$> Just 1 <*> Just []
精彩评论