Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为什么此函数的类型为(a->;a)->;A._Haskell_Types_Recursion_Anonymous_Y Combinator - Fatal编程技术网

Haskell 为什么此函数的类型为(a->;a)->;A.

Haskell 为什么此函数的类型为(a->;a)->;A.,haskell,types,recursion,anonymous,y-combinator,Haskell,Types,Recursion,Anonymous,Y Combinator,为什么这个函数的类型是(a->a)->a 它不应该是无限/递归类型吗? 我本想尝试用文字表达我认为应该是什么类型的,但由于某些原因,我就是做不到 y :: (t -> t) -> ?WTFIsGoingOnOnTheRHS? 我不知道f(yf)是如何分解成一个值的。以下内容对我来说更有意义: Prelude> let y f x = f (y f) x Prelude> :t y y :: ((a -> b) -> a -> b) -> a -&

为什么这个函数的类型是(a->a)->a

它不应该是无限/递归类型吗? 我本想尝试用文字表达我认为应该是什么类型的,但由于某些原因,我就是做不到

y :: (t -> t) -> ?WTFIsGoingOnOnTheRHS?
我不知道f(yf)是如何分解成一个值的。以下内容对我来说更有意义:

Prelude> let y f x = f (y f) x
Prelude> :t y
y :: ((a -> b) -> a -> b) -> a -> b

但它仍然令人费解。发生了什么事?

嗯,
y
必须是
(a->b)->c
,对于一些
a
b
c
我们还不知道;毕竟,它接受一个函数,
f
,并将其应用于一个参数,因此它必须是一个接受函数的函数

由于
yf=fx
(同样,对于一些
x
),我们知道
y
的返回类型必须是
f
本身的返回类型。因此,我们可以稍微细化一下
y
的类型:对于一些
a
b
我们还不知道,它必须是
(a->b)->b

为了弄清楚
a
是什么,我们只需查看传递给
f
的值的类型。它是
yf
,这是我们现在试图找出的表达式类型。我们说的是
y
的类型是
(a->b)->b
(对于一些
a
b
,等等),所以我们可以说
yf
的这个应用程序本身必须是
b
类型

因此,
f
的参数类型是
b
。把它们放在一起,我们得到了
(b->b)->b
,当然,这与
(a->a)->a
是一样的


这里有一个更直观但不太精确的观点:我们说的是
yf=f(yf)
,我们可以将其扩展为等价的
yf=f(f(yf))
yf=f(f(yf))
,等等。因此,我们知道我们总是可以在整个事情周围应用另一个
f
,并且由于所讨论的“整个事情”是将
f
应用于参数的结果,
f
必须具有
a->a
类型;由于我们刚刚得出结论,整个过程是将
f
应用于参数的结果,
y
的返回类型必须是
f
本身的返回类型-再次组合在一起,因为
(a->a)->a
@ehird在解释类型方面做得很好,我想通过一些例子来说明它是如何解析为一个值的

f1 :: Int -> Int
f1 _ = 5

-- expansion of y applied to f1
y f1
f1 (y f1)  -- definition of y
5          -- definition of f1 (the argument is ignored)

-- here's an example that uses the argument, a factorial function
fac :: (Int -> Int) -> (Int -> Int)
fac next 1 = 1
fac next n = n * next (n-1)

y fac :: Int -> Int
fac (y fac)   -- def. of y
  -- at this point, further evaluation requires the next argument
  -- so let's try 3
fac (y fac) 3  :: Int
3 * (y fac) 2             -- def. of fac
3 * (fac (y fac) 2)       -- def. of y
3 * (2 * (y fac) 1)       -- def. of fac
3 * (2 * (fac (y fac) 1)  -- def. of y
3 * (2 * 1)               -- def. of fac

您可以对任何函数执行相同的步骤,看看会发生什么。这两个例子都收敛到值,但这并不总是发生。

让我来介绍一个组合器。它被称为“不动点组合器”,具有以下特性:

属性:“不动点组合器”获取函数
f:(a->a)
,并发现该函数的“不动点”
x::a
,从而
fx==x
。不动点组合器的某些实现在“发现”方面可能更好或更差,但假设它终止,它将生成输入函数的固定点。任何满足该属性的函数都可以称为“不动点组合子”

称之为“定点组合器”
y
。根据我们刚才所说的,以下是事实:

-- as we said, y's input is f :: a -> a, and its output is x :: a, therefore
y :: (a -> a) -> a

-- let x be the fixed point discovered by applying f to y
y f == x -- because y discovers x, a fixed point of f, per The Property
f x == x -- the behavior of a fixed point, per The Property

-- now, per substitution of "x" with "f x" in "y f == x"
y f == f x
-- again, per substitution of "x" with "y f" in the previous line
y f == f (y f)
好了。您已经根据不动点组合符的基本属性定义了
y

yf==f(yf)
。与假设
yf
发现
x
不同,您可以假设
x
表示一个发散的计算,并且仍然得出相同的结论(iinm)

由于您的函数满足该属性,我们可以得出结论,它是一个不动点组合子,并且我们所述的其他属性(包括类型)适用于您的函数


这并不是一个确切的证据,但我希望它能提供更多的见解。

只需对其他人的答案补充两点

您定义的函数通常称为
fix
,它是一个:计算另一个函数的。在数学中,函数
f
的不动点是一个参数
x
,使得
fx=x
。这已经允许您推断
fix
的类型必须是
(a->a)->a
;函数,它将函数从
a
转换为
a
,并返回
a

您调用了函数
y
,它似乎在后面,但这是一个不准确的名称:y组合子是一个特定的固定点组合子,但与您在此处定义的不同

我不知道f(yf)是如何分解成一个值的

好吧,诀窍在于Haskell是一种非严格(又称“懒惰”)语言。如果在所有情况下
f
不需要计算其
yf
参数,则
f(yf)
的计算可以终止。因此,如果定义阶乘(如John L所示),
fac(y fac)1
计算为1,而不计算
y fac


严格的语言无法做到这一点,因此在这些语言中,您不能用这种方式定义定点组合符。在这些语言中,教科书中的定点组合符就是Y组合符。

假设这是真实的代码,那么不管是谁提出的,就解雇他。@MartinJames:嗯?你认为代码有什么问题?“这不是定义函数的最佳方法,但它是最简单的。”MartinJames,该函数是一个经过充分研究的函数,称为。(我想这是对的-我现在不能再检查维基百科!)不管怎样,也许你会因为如此庸俗而被解雇:-@AaronMcDaid:它实际上不是Y组合符,它只是等价于它;这是一个具有显式命名递归的定点函数,而Y combinator的创新之处是在没有任何语言支持的情况下实现递归。请注意,尝试添加
?banner=none-- as we said, y's input is f :: a -> a, and its output is x :: a, therefore
y :: (a -> a) -> a

-- let x be the fixed point discovered by applying f to y
y f == x -- because y discovers x, a fixed point of f, per The Property
f x == x -- the behavior of a fixed point, per The Property

-- now, per substitution of "x" with "f x" in "y f == x"
y f == f x
-- again, per substitution of "x" with "y f" in the previous line
y f == f (y f)