我似乎无法理解id
如何用作某些高阶函数的参数。我曾经在某个地方读到过这样的习惯,就是单独留下一些东西"但似乎无法理解它。
例如,为什么liftA2 id
f (b -> c) -> f b -> f c
的类型?
另外,为什么我无法将id
传递给g
g :: (Int -> Int -> Int) -> Int -> Int -> Int
答案 0 :(得分:5)
我已经在某个地方读过[
id
]已经习惯了#34;留下一些东西"但似乎无法理解它。
id
用于"留下一些东西"因为这就是它所做的一切 - 也就是说,没有:
id :: x -> x
id x = x
就是这样,id
经常显示为传递给高阶函数的do-nothing占位符。 fmap id foo
实际上并未更改foo
内的值(事实上,fmap id = id
,这是第一个仿函数法律),id . f
和f . id
都等于f
,等等。一个更有趣的示例是the classic trick of defining foldl
using foldr
,其中id
用作构建foldr
函数的基本案例。
例如,为什么
liftA2 id
f (b -> c) -> f b -> f c
的类型?
liftA2
的类型是:
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
在liftA2 id
的情况下,我们有......
(a -> (b -> c)) ~ (x -> x)
......等等......
a ~ x
(b -> c) ~ x
......因此......
liftA2 id :: f (b -> c) -> f b -> f c
(正如您可能知道的那样,liftA2 id = (<*>)
。如果您将其写为liftA2 ($)
,($) :: (a -> b) -> (a -> b)
仅仅是一个专门的id
,那么发生的事情可能会更明显。)
另外,为什么我无法将
id
传递给g
g :: (Int -> Int -> Int) -> Int -> Int -> Int
因为那时你必须统一......
(Int -> (Int -> Int)) ~ (x -> x)
...这是不可能的,因为x
不能同时为Int
和Int -> Int
。