[英]“foo” is “a -> b -> c”. “foo . foo” is also “a -> b -> c”. Does Haskell treat them exactly the same in terms of speed?
[英]Are there any use cases for this function : foo :: (b -> c) -> (a -> b) -> (a -> c)
對於此功能:
foo :: (b -> c) -> (a -> b) -> (a -> c)
取自http://www.seas.upenn.edu/~cis194/spring13/lectures/04-higher-order.html
這是沒有實際用途的功能嗎? 除非類型c是此函數中的另一個輸入參數,否則無法構造(b -> c)
?
與(a -> b) -> (a -> c)
:b和c不是這些函數的輸入參數。
此功能有用例嗎?
如果問題是關於在實踐中使用函數組合的,那么這里是一個小例子。 假設我們要編寫一個函數,該函數將數字列表的所有元素的平方和。 我們該怎么做? 好吧,我們可以這樣寫: squareSum xs = sum (map (^2)) xs
。 但是我們也可以改用函數組合: squareSum = sum . map (^2)
squareSum = sum . map (^2)
(我在函數組合中使用.
而不是foo
,但這並不重要)。 此示例顯示了使用函數組合獲得的函數(至少在某種意義上說它可以正確編譯和正常工作是可行的)。 當我們需要組合多個功能(可能部分應用)時,功能組合的好處變得更加明顯。
可以構造函數b -> c
由於b
和c
可以是任何類型,因此任何函數都與之兼容。 但是,由於函數foo
不了解b
和c
因此它本身不能(明智地)構造此類函數。 這是一個很大的好處,因為它大大減少了函數foo
的可能實現數量。 這稱為參數性
此函數是函數組合運算符(.)
:
我只是想補充一下(.)
可能在任何良好的Haskell代碼庫中使用最多的前三個函數中。 它肯定在我的代碼中。
前三名中的另外兩個是由於整數而由編譯器插入的對fromInteger
隱式調用,以及對來自do
表示法的(>>=)
隱式調用。 從深度上講,后者的操作與(.)
相同,但類型略有不同的值。
為了補充其他答案,讓我嘗試證明只有一個(全部)功能
foo :: (b -> c) -> (a -> b) -> (a -> c)
或者換句話說, foo = (.)
。 通過擴展性,我們想證明
foo f g n = f (g n)
其中f,g,n
是foo
簽名所要求的類型的縮寫值。
f :: b -> c
g :: a -> b
n :: a
我們從相關的自由定理開始,該定理可以在網絡上自動生成 :
forall t1,t2 in TYPES, R in REL(t1,t2).
forall t3,t4 in TYPES, S in REL(t3,t4).
forall t5,t6 in TYPES, R1 in REL(t5,t6).
forall p :: t3 -> t5.
forall q :: t4 -> t6.
(forall (x, y) in S. (p x, q y) in R1)
==> (forall r :: t1 -> t3.
forall s :: t2 -> t4.
(forall (z, v) in R. (r z, s v) in S)
==> (forall (w, u) in R.
(foo p r w, foo q s u) in R1))
讓我們通過專門化它來簡化這個龐大的公式。 我們選擇:
t1 = a t2 = ()
t3 = b t4 = ()
t5 = c t6 = ()
我們選擇以下關系:
R = { (n , ()) } which is indeed in REL(t1,t2) = REL(a,())
S = { (g n , ()) } which is indeed in REL(t3,t4) = REL(b,())
R1= { (f (g n) , ()) } which is indeed in REL(t5,t6) = REL(c,())
自由定理變為:
forall p :: b -> c.
forall q :: () -> ().
(forall (x, y) in S. (p x, q y) in R1)
==> (forall r :: a -> b.
forall s :: () -> ().
(forall (z, v) in R. (r z, s v) in S)
==> (forall (w, u) in R.
(foo p r w, foo q s u) in R1))
根據S
和R1
定義,我們選擇p = f
和q = id
:
(forall x = g n, y = () . f x = f (g n) /\ y = id y)
==> (forall r :: a -> b.
forall s :: () -> ().
(forall (z, v) in R. (r z, s v) in S)
==> (forall (w, u) in R.
(foo f r w, foo id s u) in R1))
頂層含義的前提是正確的,因此我們將其消除。 現在,我們選擇r = g
和s = id
。 根據r1
和R
定義,我們得到:
(forall z = n, v = () . g z = g n , id v = ())
==> (forall (w, u) in R.
(foo f g w, foo id id u) in R1)
我們可以釋放真正的前提。 此外,我們可以選擇w = n
和u = ()
。 我們最終獲得:
foo f g n = f (g n) /\ foo id id u = ()
優質教育
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.