我有一个表示某个状态的值元组,并希望通过加法(shift)来翻译它。我的值是(Int,[Int],Int)的更长版本,我想要一些概念上(但不是字面意思)的东西:
shift n = ??? (+n) (id, map, id) -- simple(?)
这相当于:
shift n (a, b, c) = (a+n, map (+n) b, c+n)
我很高兴能够使用这个明确的函数用法,但我想知道有一个更惯用的无点版本使用Applicative或Arrows或......,或者如果它们最终会混淆一些东西。我认为无点版本更清楚地显示了操作的基本结构。
答案 0 :(得分:5)
你可以写
shift n (a,b,c) = (a+n, map (+n) b, c+n)
或者定义类似于箭头(***)
和(&&&)
的新组合器,
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) )
答案 1 :(得分:4)
使用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)
长,所以你可能想用记录语法定义你的状态类型。)
答案 2 :(得分:1)
将列表功能应用于列表值只是
zipWith ($)
由于不同大小的元组都是它们自己的类型,因此您必须为3元组显式编写函数。将3元组函数应用于3元组值的一般函数是
apply (f, g, h) (a, b, c) = (f a, g b, h c)
您必须显式编写每个函数应用程序,因为元组没有列表的递归属性。