綜觀($)
和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
綜觀($)
和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
漂亮其實很簡單:
($) :: (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
。統一term1
和term2
當http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse5 總結的統一算法,:
例如,我們可以寫一個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.
一個統一的算法可以在這裏找到:
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
。這是不相容的。因此這兩個術語不統一。Unflipped $
在其右側得到a
類型的值,並且它適用於從它的左側的功能(a -> b)
:func $ value
相同func value
。
翻轉$
需要b
類型的值在其左側和從其右側施加函數(b->c)
它:value `flip ($)` func
相同func value
。
行了相應類型的組件:
($) :: (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
你是怎麼知道(a - > b)被應用於flip的第一個參數的? – 2014-11-25 02:35:05
我編輯了我的答案。 'flip'的第一個也是唯一的參數是'(a - > b - > c)'。這並不是說'(a - > b)'適用於'a'。更像是(a - > b - > c)與'(a - > b) - > a - > b'統一。因此'a'與'(a - > b)'統一。 – 2014-11-25 02:48:38
偉大的圖表。不清楚給算法提供多大幫助,但我想它不會受到傷害。 – luqui 2014-11-25 06:23:11