【问题标题】:Haskell - apply tuple of functions to tuple of values?Haskell - 将函数元组应用于值元组?
【发布时间】:2014-11-23 09:23:38
【问题描述】:

我有一个表示某种状态的值元组,并希望通过加法(移位)来翻译它。我的值是 (Int, [Int], Int) 的更长版本,我想要一些概念上(但不是字面意思)的东西:

shift n = ??? (+n) (id, map, id)     -- simple(?)

相当于:

shift n (a, b, c) = (a+n, map (+n) b, c+n)

我很高兴使用这种显式的函数用法,但想知道是否有一个更惯用的无点版本使用 Applicative 或 Arrows 或 ...,或者它们是否最终会混淆事物。我认为无点版本更清楚地显示了操作的基本结构。

【问题讨论】:

    标签: function haskell tuples apply pointfree


    【解决方案1】:

    list 函数应用于 list 值很简单

    zipWith ($)
    

    由于不同大小的元组都是各自的类型,因此您必须为 3 元组显式编写函数。将三元组函数应用于三元组值的一般函数是

    apply (f, g, h) (a, b, c) = (f a, g b, h c)
    

    您必须显式编写每个函数应用程序,因为元组不具有列表的递归属性。

    【讨论】:

      【解决方案2】:

      你可以写

      shift n (a,b,c) = (a+n, map (+n) b, c+n)
      

      或者定义类似于Arrow的(***)(&&&)的新组合子,

      prod3 (f,g,h) (a,b,c) = (f a, g b, h c)     -- cf. (***)
      call3 (f,g,h)  x      = (f x, g x, h x)     -- cf. (&&&)
      ap3    f      (a,b,c) = (f a, f b, f c)
      uncurry3  f   (a,b,c) =  f a    b    c
      

      然后调用

      prod3 ( (+n), map (+n), (+n) ) (a,b,c)
      

      甚至(适当设置运算符优先级)

      ap3 ($ (+n)) (id, map, id) `prod3` (a,b,c)
      

      或者,如果你将你的三元组写成嵌套对,你可以使用

      Prelude Control.Arrow> ( (+5) *** map (+5) *** (+5) ) (1,([2,3],4))
      (6,([7,8],9))
      

      所以对于嵌套对,

      shift' :: (Num b) => b -> (b, ([b], b)) -> (b, ([b], b))
      shift' n = ( (+n) *** map (+n) *** (+n) )
      

      (另见Multiple folds in one pass using generic tuple function

      【讨论】:

      • 谢谢;嵌套对是一个好主意,我试过了,但是状态较长(四个项目)它很混乱,而且对于这种情况并不是最好的。我想知道 *** 的概括,但似乎不是。
      • 当我尝试过这种方法时:( (+5) *** map (+5) *** (+5) ) 我想知道是否有一种简单的方法来反应常见的操作( +n) 超出定义(参见原始问题)。
      • 好吧,(f *** (f *** f)) = (***) f ( (***) f f ) = (***) f (join (***) f) = ( (***) <*> join (***) ) f。对于 4 元组 ((a,b),(c,d)) 形,它将是 (join (***) <*> join (***)) f
      【解决方案3】:

      使用DeriveFunctor 语言扩展,您可以编写

      data MyState a = MyState a [a] a
          deriving (Functor)
      

      派生实例的样子

      instance Functor MyState where
          fmap f (MyState a bs c) = MyState (f a) (map f bs) (f c)
      

      现在你可以定义

      shift :: MyState Int -> MyState Int
      shift n = fmap (+n)
      

      (你说你的元组比(Int, [Int], Int)还要长,所以你可能想用记录语法来定义你的状态类型。)

      【讨论】:

      • 谢谢;我知道我可以做到这一点,也许它是“最好的”解决方案,但如果没有当前的运算符,那么最好只编写函数。我在考虑类似 *** 的概括。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多