вариационная привязка в Хаскеле - PullRequest
4 голосов
/ 16 октября 2011

Следующий код является попыткой написать переменную функцию, которая действует следующим образом:

  • bind_variadic mx f = mx >>= f
  • bind_variadic mx my f = do { x <- mx; y <- my; f x y }

IЯ могу написать его, если один выражает «остаток связывания» как переменную k, но для того, чтобы написать класс типов, мне нужно написать одну функцию в терминах другой.Чтобы быть точным, я хочу выразить l1 в терминах l0, l2 в терминах l1 и т. Д.

import Prelude hiding ((>>=), (>>), Monad, return)

-- override the default monad so we don't get confusing
-- instances like "Monad (->)".
class Monad m where
  (>>=) :: m a -> (a -> m b) -> m b
  (>>) :: m a -> m b -> m b
  return :: a -> m a
  fail :: String -> m a

h :: Monad m => m a -> (t -> m b) -> (a -> t) -> m b
h mx k f = mx >>= \x -> k (f x)

l0 = h (return 3) id (\x -> return x)
l1 = h (return 3) (h (return 4) id) (\x y -> return x)
l2 = h (return 3) (h (return 4) (h (return 5) id)) (\x y z -> return x)

Возможно, решение предполагает другое продолжение?

edit

вот идея, которая требует дополнительного соединения ...

-- if not using Control.Monad, use this
join :: Monad ? => ? (? α) -> ? α
join mx = mx >>= id

-- idea: get side effects of evaluating first arguments first
h' mz k f = k f >>= \f' -> mz >>= (return . f')

l1' = h' (return 3) return
unary = join (l1' (\x -> return x))
l2' = h' (return 4) l1'
binary = join (l2' (\x y -> return x))
l3' = h' (return 5) l2'
ternary = join (l3' (\x y z -> return x))

1 Ответ

1 голос
/ 16 октября 2011

Если вы хотите выразить это:

ap_variadic mx f = mx >>= f
ap_variadic mx my f = do { x <- mx; y <- my; f x y }

Я бы использовал Control.Applicative вместо этого.Тогда:

join (f <$> mx)
join (f <$> mx <*> my)
join (f <$> mx <*> my <*> mz)

Я думаю, что это лучше (проще, удобнее в обслуживании), чем любое поливариадное решение.

...