查看($)
和flip
的类型:
ghci> :t ($)
($) :: (a -> b) -> a -> b
ghci> :t flip
flip :: (a -> b -> c) -> b -> a -> c
您能否向我解释flip ($)
如何签名?
ghci> :t flip ($)
flip ($) :: b -> (b -> c) -> c
答案 0 :(得分:12)
非常简单:
($) :: (a -> b) -> a -> b
|______| | |
| | |
flip :: (a -> b -> c) -> b -> a -> c
因此,我们基本上将(a -> b -> c)
与(a -> b) -> a -> b
统一起来。为清楚起见,我们将(a -> b -> c)
重命名为(r -> s -> t)
:
($) :: (a -> b) -> a -> b
|______| | |
| | |
flip :: (r -> s -> t) -> s -> r -> t
因此:
r
与(a -> b)
结合使用。s
与a
结合使用。t
与b
结合使用。因此:
flip ($) :: s -> r -> t
:: a -> (a -> b) -> b
这相当于:
flip ($) :: b -> (b -> c) -> c
这就是它的全部内容。
修改强>
flip
函数有一个参数(a -> b -> c)
和一个返回值b -> a -> c
。flip ($)
时,($)
函数将成为flip
函数的第一个参数。($)
的类型签名为unified,其参数类型为flip
。(a -> b -> c)
和(a -> b) -> a -> b
。(a -> b -> c)
首先重命名为(r -> s -> t)
,然后用r
代替(a -> b)
,s
代替a
}和t
代替b
。例如,我们可以编写一个Prolog程序来统一术语:
% fun(R, fun(S, T)) is equivalent to (r -> s -> t).
% fun(fun(A, B), fun(A, B)) is equivalent to (a -> b) -> a -> b.
?- fun(R, fun(S, T)) = fun(fun(A, B), fun(A, B)).
R = fun(A, B),
S = A,
T = B.
可以在此处找到统一算法:http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse5
在统一term1
和term2
时总结统一算法:
term1
和term2
是常量,那么当且仅当它们是相同的常量时,它们才会统一。例如,Int
仅与常量Int
统一。它并不与常量Char
统一。term1
是变量而term2
是非变量,那么term1
将被term2
实例化(即term1 := term2
)。例如,a
和Int
与a := Int
统一。term2
是变量而term1
是非变量,那么term2
将被term1
实例化(即term2 := term1
)。例如,Int
和b
与b := Int
统一。term1
和term2
都是变量,那么它们都会相互实例化,并且据说它们共享值(即term1 := term2
和term2 := term1
)。例如,统一时,a
和b
将成为同一个变量。term1
和term2
是复杂的术语(例如term1
是Either a Int
而term2
是Either Char b
),那么他们会统一除非:
Maybe Int
和Maybe Char
具有相同的类型构造函数。但是,Maybe Int
和[Int]
没有。Either a Int
和Either Char b
中,参数与a := Char
和b := Int
统一。Either a a
与Either Char Int
统一时,我们先是a := Char
,然后是a := Int
。这是不兼容的。因此这两个词没有统一。答案 1 :(得分:4)
排列类型的相应组件:
($) :: (a -> b) -> a -> b
flip :: (a -> b -> c) -> b -> a -> c
重要规则:在任何类型的签名中,您可以将类型变量的每个匹配项替换为不会出现在同一签名中的任何位置,并获得与原始类型完全等效的类型。 (类型不关心类型变量的名称,只关注哪些变量相同以及哪些变量在同一签名中是不同的。)因此,我们可以在flip
(a := x
中稍微重命名类型变量,b := y
,c := z
),它们的类型相同:
($) :: (a -> b) -> a -> b
flip :: (x -> y -> z) -> y -> x -> z
略有不同的规则:在任何类型的签名中,我们可以用任何类型替换类型变量的所有实例,并获得该类型的专用版本。我们将flip
专门化为使其与($)
兼容的类型。我们通过替换x := (a -> b)
,y := a
和z := b
:
($) :: (a -> b) -> a -> b
flip :: ((a -> b) -> a -> b) -> a -> (a -> b) -> b
既然这个专业版flip
的第一个参数的类型与($)
的类型匹配,我们就可以找出flip ($)
的类型:
flip ($) :: a -> (a -> b) -> b
现在我们替换b := c
,然后替换a := b
:
flip ($) :: b -> (b -> c) -> c
答案 2 :(得分:2)
未翻转的$
在其右侧获取a
类型的值,并将其应用于左侧的(a -> b)
函数:func $ value
与{{func value
相同1}}。
翻转$
在其左侧采用b
类型的值,并将右侧的函数(b->c)
应用于它:value `flip ($)` func
与{{func value
相同1}}。