Curry / Uncurry monad变压器起重

时间:2018-05-15 14:52:26

标签: haskell functional-programming

我正在编写一些lift函数,这些函数采用记录字段函数,一些参数,然后lift将记录中存储的操作Monad转移到另一个liftCapability :: Has capability e => ( capability -> IO a ) -> ReaderT e IO a liftCapability f = do capability <- asks getter lift $ f capability ,其中I&#39;我在工作:

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 函数的地方,每个函数用于不同的arity:

curryN

有没有办法抽象出作为eta-reduce的函数的最后一个参数的应用?

到目前为止,我已尝试使用tuple package中的uncurryNliftC f = liftC' f . curryN where liftC' f a = do c <- asks getter lift $ (f c) (uncurryN a) ,但这不起作用,因为它不能讨论少于两个参数:< / p>

'parent_id'     => [
    'type'        => Form::INPUT_WIDGET,
    'widgetClass' => '\kartik\widgets\Select2',
    'options'     => [
        'data'        => ArrayHelper::map(app\models\FinancialAccounts::find()
            ->all(), 'account_id', 'account_name'),
        'options'       => ['placeholder' => '...'],
        'pluginOptions' => ['allowClear' => true],
    ]
],

这是可能的,还是我注定每个人都有一个功能?

1 个答案:

答案 0 :(得分:0)

一种解决方案是更改您使用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