Автоматический перенос инфиксных операторов на монадные инфиксные операторы - PullRequest
9 голосов
/ 12 октября 2011

Одна из приятных особенностей Haskell - возможность использовать инфиксную запись.

1 : 2 : 3 : []    :: Num a => [a]
2 + 4 * 3 + 5     :: Num a => a

Но эта мощность внезапно и печально теряется, когда оператора нужно поднять.

liftM2 (*) (liftM2 (+) m2 m4) (liftM2 (+) m3 m5)
liftM2 (:) m1 (liftM2 (:) m2 (liftM2 (:) m3 mE))

Можно определить аналогичные операторы для восстановления этой власти

(.*) = 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

Но утомительно, когда нужно переименовать каждый оператор, который я хочу использовать, в монадическом контексте. Есть ли способ лучше? Шаблон Haskell, возможно?

Ответы [ 3 ]

10 голосов
/ 12 октября 2011

Вы можете сделать все экземпляры монад 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 (*)

Тогда вы можете сделать f.e.:

*Main> [3,4] * [5,6] + [1,2]
[16,17,19,20,21,22,25,26]

Но это работает только для операторов, которые определены с классами типов. С : это невозможно.

9 голосов
/ 12 октября 2011

Вы можете определить новый инфиксный лифт:

v <. f = liftM2 f v
f .> v = f v

Пример использования:

[3] <.(+).> [4]

... но я не знаю ни одного реального способа, который бы не был 100% раздражает.

2 голосов
/ 12 октября 2011

Существует стиль, использующий ap:

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

или аппликативный стиль:

(:) <$> Just 1 <*> Just []
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...