6

我正在尝试找到一种方法来做这样的事情:

(head, last) `someFunction` [1, 2, 3]

生成元组(1, 3)作为输出。

它在理论上似乎类似于应用函子,但有点倒退。我猜有一个类似的功能可以做到这一点(或某种方法),但我似乎无法找到它/弄明白。

我尝试定义这样的函数:

fmap' :: ((a -> b), (a -> b)) -> [a] -> (b, b)
fmap' (f1, f2) xs = (f1 xs, f2 xs)

但 GHC 实际上不会编译这个。

任何帮助都会很棒;谢谢!

编辑(一年后!):

fmap'不会编译,因为类型签名是错误的。显然有更好的方法来做我正在做的事情,但我的类型fmap'应该是:

fmap' :: ((a -> b), (a -> b)) -> a -> (b, b)

在这种情况下,它编译并运行得很好。

4

4 回答 4

15

我认为你可以用箭头做到这一点。

head &&& last $ [1,2,3]

将返回(1,3)

于 2012-07-27T19:38:30.400 回答
9

它在理论上似乎类似于应用函子,但有点倒退。

实际上,这是一个无聊的老前锋应用函子;具体来说,读者((->) r)

Prelude Control.Applicative> liftA2 (,) head last [1,2,3]
(1,3)

或者,如果你喜欢这样的事情:

Prelude Control.Applicative> let sequenceA [] = pure []; sequenceA (x:xs) = (:) <$> x <*> sequenceA xs
Prelude Control.Applicative> [head, last] `sequenceA` [1,2,3]
[1,3]
于 2012-07-27T19:47:42.983 回答
4

类型fmap'不对。它应该是

fmap' :: ([a] -> b, [a] -> b) -> [a] -> (b, b)

或者,它可以更概括

fmap' :: (a -> b, a -> c) -> a -> (b, c)

真的不像fmap :: (a -> b) -> f a -> f b

于 2012-07-27T19:20:01.110 回答
3

在这种情况下可以尝试的方法是省略类型签名并检查 GHC 推断的内容。

这样做并询问 GHCi:t fmap'会产生签名

fmap' :: (t2 -> t, t2 -> t1) -> t2 -> (t, t1)

这与 KennyTM 的通用版本相同,将为您提供您正在寻找的行为。

于 2012-07-27T19:32:50.853 回答