Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatic lifting of infix operators to monadic infix operators

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?

like image 866
Dan Burton Avatar asked Oct 12 '11 15:10

Dan Burton


3 Answers

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.

like image 53
Sjoerd Visscher Avatar answered Nov 11 '22 07:11

Sjoerd Visscher


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.

like image 21
Daniel Wagner Avatar answered Nov 11 '22 08:11

Daniel Wagner


There is the style using ap:

return (:) `ap` Just 1 `ap` Just []

or applicative style:

(:) <$> Just 1 <*> Just []
like image 2
u0b34a0f6ae Avatar answered Nov 11 '22 09:11

u0b34a0f6ae