高阶函数和id

Sha*_*pta 2 haskell higher-order-functions

我似乎无法理解如何id将其用作某些高阶函数的参数.我曾经在某个地方读到它曾经"习惯于"留下一些东西",但似乎无法理解它.

例如,为什么是这种类型的liftA2 id f (b -> c) -> f b -> f c

另外,为什么我不能传递idg

g :: (Int -> Int -> Int) -> Int -> Int -> Int
Run Code Online (Sandbox Code Playgroud)

dup*_*ode 5

我读过某个地方[ id]习惯于"留下一些东西",但似乎无法理解它.

id 用来"留下一些东西",因为这就是它所做的一切 - 也就是说,没有:

id :: x -> x
id x = x
Run Code Online (Sandbox Code Playgroud)

既然如此,id往往表现为一个无所事事的占位符传递给高阶函数.fmap id foo实际上并没有改变其中发现的值foo(事实上​​,fmap id = id这是第一个算子法),id . f并且f . id都等同于f等等.一个更有趣的例子是定义foldl使用的经典技巧foldr,其中id用作构建函数的基础案例foldr.

例如,为什么是这种类型的liftA2 id f (b -> c) -> f b -> f c

类型liftA2是:

liftA2 :: (a -> b -> c) -> f a -> f b -> f c
Run Code Online (Sandbox Code Playgroud)

在这种情况下liftA2 id,我们有......

(a -> (b -> c)) ~ (x -> x)
Run Code Online (Sandbox Code Playgroud)

... 所以...

a ~ x
(b -> c) ~ x
Run Code Online (Sandbox Code Playgroud)

......因此......

liftA2 id :: f (b -> c) -> f b -> f c
Run Code Online (Sandbox Code Playgroud)

(正如你可能知道,liftA2 id = (<*>).这是怎么回事,也许更明显,如果你把它写成liftA2 ($),($) :: (a -> b) -> (a -> b)是仅仅是一个专门的id.)

另外,为什么我不能传递idg

g :: (Int -> Int -> Int) -> Int -> Int -> Int
Run Code Online (Sandbox Code Playgroud)

因为那时你必须统一......

(Int -> (Int -> Int)) ~ (x -> x)
Run Code Online (Sandbox Code Playgroud)

......这是不可能的,因为x不可能同时IntInt -> Int.

  • 要想直观地阅读"你必须统一......",试试这个.`id`可以单独留下一个`Int`并且具有类型`Int - > Int`(它与`g`的参数具有相同的参数类型); 或者`id`可以单独留下`Int - > Int`函数,并且类型为`(Int - > Int) - >(Int - > Int)`aka`(Int - > Int) - > Int - > Int`(这与`g`的参数具有相同的结果类型.但是,与人类不同,如果你试图单独留下两个`Int`s,你不会在另一端只得到一个`Int`,所以`id`不能有类型`Int - > Int - > Int `. (2认同)