Curry / Uncurry монад трансформатор подъема - PullRequest
0 голосов
/ 15 мая 2018

Я пишу некоторые lift функции, которые принимают функцию поля записи, некоторые параметры и затем lift действие, сохраненное в записи, в другой Monad, где я работаю:

liftCapability :: Has capability e
                => ( capability -> IO a )
                -> ReaderT e IO a
liftCapability f = do
  capability <- asks getter
  lift $ f capability

Проблема в том, что я прибыл в место, где у меня есть множество этих lift функций, каждая из которых предназначена для разной арности, если мне нужно вызвать ее с большим количеством параметров:

liftCapability1 :: Has capability e
                => ( capability -> a -> IO b )
                -> a
                -> ReaderT e IO b
liftCapability1 f a = do
  capability <- asks getter
  lift $ f capability a


liftCapability2 :: Has capability e
                => ( capability -> a -> b -> IO c )
                -> a
                -> b
                -> ReaderT e IO c
liftCapability2 f a b = do
  capability <- asks getter
  lift $ f capability a b

Есть лиспособ абстрагировать применение последних аргументов функции, которая работала как eta-Reduce?

До сих пор я пытался использовать curryN и uncurryN из пакета tuple , но это не сработает, так как не может содержать менее двух аргументов:

liftC f =
  liftC' f . curryN
 where
  liftC' f a = do
    c <- asks getter
    lift $ (f c) (uncurryN a)

Возможно ли это, или я обречен иметь функцию на арность?

1 Ответ

0 голосов
/ 15 мая 2018

Одним из решений является изменение порядка аргументов функций, для которых вы используете liftCapability.

λ :t \f b -> liftCapability $ \x -> f x b
\f b -> liftCapability $ \x -> f x b                        
  :: Has t1 e => (t1 -> t2 -> IO a) -> t2 -> ReaderT e IO a 
λ :t \f c b -> liftCapability $ \x -> f x c b
\f c b -> liftCapability $ \x -> f x c b                           
  :: Has t1 e =>                                                   
     (t1 -> t2 -> t3 -> IO a) -> t2 -> t3 -> ReaderT e IO a        

Другой вариант - использовать класс типов

{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, TypeFamilies #-}
-- ...
class LiftableCapability v where
   type Low v :: *
   type Env v :: *
   liftCapability :: Has capability (Env v) => (capability -> Low v) -> v

instance LiftableCapability (ReaderT e IO a) where
   type Low (ReaderT e IO a) = IO a
   type Env (ReaderT e IO a) = e
   liftCapability f = lift . f =<< asks getter

instance LiftableCapability v => LiftableCapability (a -> v) where
   type Low (a -> v) = a -> Low v
   type Env (a -> v) = Env v
   liftCapability f = liftCapability . flip f
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...