Haskell - 将函数元组应用于值元组?

gut*_*rie 4 haskell tuples function apply pointfree

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

shift n = ??? (+n) (id, map, id)     -- simple(?)
Run Code Online (Sandbox Code Playgroud)

这相当于:

shift n (a, b, c) = (a+n, map (+n) b, c+n)
Run Code Online (Sandbox Code Playgroud)

我很高兴能够使用这个明确的函数用法,但是想知道它有一个更惯用的无点版本使用Applicative或Arrows或......,或者如果它们最终会混淆一些东西.我认为无点版本更清楚地显示了操作的基本结构.

Wil*_*ess 5

你可以写

shift n (a,b,c) = (a+n, map (+n) b, c+n)
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

然后打电话

prod3 ( (+n), map (+n), (+n) ) (a,b,c)
Run Code Online (Sandbox Code Playgroud)

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

ap3 ($ (+n)) (id, map, id) `prod3` (a,b,c)
Run Code Online (Sandbox Code Playgroud)

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

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

所以对于嵌套对,

shift' :: (Num b) => b -> (b, ([b], b)) -> (b, ([b], b))
shift' n = ( (+n) *** map (+n) *** (+n) )
Run Code Online (Sandbox Code Playgroud)

(另请参阅使用通用元组函数的一次传递中的多个折叠)


Rei*_*ton 4

通过DeriveFunctor语言扩展,您可以编写

data MyState a = MyState a [a] a
    deriving (Functor)
Run Code Online (Sandbox Code Playgroud)

派生实例看起来像

instance Functor MyState where
    fmap f (MyState a bs c) = MyState (f a) (map f bs) (f c)
Run Code Online (Sandbox Code Playgroud)

现在您可以定义

shift :: MyState Int -> MyState Int
shift n = fmap (+n)
Run Code Online (Sandbox Code Playgroud)

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