[英]Haskell- Placement of variables of functions in functions and `where` statements
我知道這不是最好的解釋,但我正在盡力而為。
我正在努力理解 haskell 中變量和函數的位置, where
關鍵字和 function 在 function 類型的代碼中。
以這段代碼為例。
dummy :: Num a => a -> a -> a -> a
dummy v e = dum
where
dum a@x = v + e + a
我認為第一個 function 只是在存儲變量 v 和 e 的內部執行。 使用存儲 a@x 的 dum 執行主體,執行添加的主體。
下面的代碼應該采用有序列表並在正確的位置插入一個值。
如果我像這樣使用它,請insert' 6 [5, 7, 8]
。 我以為 6 == x 和 6 == [x]。 但是如果它需要一個起始值,那么它是如何工作的。 因為第三個代碼塊顯示了這個過程。 老師說[6]
是起始值,但我似乎無法在 foldr 中使用列表作為起始值。
總之:有兩個輸入,它們放置在 function 的主體中。 foldr 如何在這里工作。
insert' :: Ord a => a -> [a] -> [a]
insert' x = foldr insx [x]
where
insx y ys@(z:zs) | z==x && x<y = z:y:zs
| otherwise = y:ys
5 `insx` (7 `insx`(8 `insx` [6]))
5 `insx` (7 `insx`(insx 8 [6])) -- 6==6 && 6<8 = 6:8:[]
5 `insx` (insx 7 6:8:[]) -- 6==6 && 6<7 = 6:7:8:[]
insx 5 (6:7:8:[]) -- otherwise = 5:6:7:8:[]
我將通過您的示例逐步評估 go:
insert' :: Ord a => a -> [a] -> [a]
insert' x = foldr insx [x]
where
insx y ys@(z:zs) | z==x && x<y = z:y:zs
| otherwise = y:ys
insert' 6 [5, 7, 8]
等價於(insert' 6) [5, 7, 8]
因為 function 應用程序關聯到左側。
根據 insert' 的定義, insert'
insert' 6
等於x
= 6
的foldr insx [6]
。
這稱為eta-reduction ,以 lambda 演算中的“eta 規則”命名。 基本上這意味着如果你有一個 function 可以這樣寫:
f x = g x
其中g
是某個表達式,那么如果g
不包含x
,您可以將其簡化為f = g
,因為f
只是將其參數直接傳遞給g
。 例如:
add x y = x + y
-- by definition of infix operators:
add x y = (+) x y
-- by left-association of function application:
add x y = ((+) x) y
-- eta-reduce:
add x = (+) x
-- eta-reduce again:
add = (+)
因此, Int -> Int -> Int
類型的“雙參數”定義也可以被認為是返回單參數 function Int -> (Int -> Int)
或零參數的單參數定義定義(一個變量),它是一個“雙參數” function (Int -> Int -> Int)
。 關鍵是所有函數都只有一個參數,我們只是為多參數函數鏈提供了一些語法糖。
因此,您示例中的整個表達式等於(foldr insx [6]) [5, 7, 8]
。 因為 function 應用程序是左關聯的,括號是多余的,所以這與foldr insx [6] [5, 7, 8]
相同。 所以foldr
在這里得到了充分的應用。
foldr 的評估然后擴展到以下內容:
insx 5 (insx 7 (insx 8 [6]))
並且您可以為每個參數組合擴展insx
的定義。 我將從最右邊的insx
調用開始,即insx 8 [6]
,它在列表的語法上相當於insx 8 (6:[])
。
根據insx
的定義, y
= 8
、 ys
= [6]
、 z
= 6
和zs
= []
。 所以第一個守衛是z == x && x < y
= 6 == 6 && 6 < 8
,這是真的,所以結果是z:y:zs
= 6:8:[]
= [6, 8]
。
這給出了insx 5 (insx 7 [6, 8])
。 最右邊的調用insx 7 [6, 8]
設置y
= 7
、 ys
= [6, 8]
、 z
= 6
和zs
= [8]
。 守衛評估為6 == 6 && 6 < 7
再次為真,給出6:7:[8]
= [6, 7, 8]
。
最后我們有insx 5 [6, 7, 8]
。 現在y
= 5
, ys
= [6, 7, 8]
, z
= 6
和zs
= [7, 8]
。 守衛是6 == 6 && 6 < 5
,這是false ,所以我們繼續下一個守衛。 otherwise
總是正確的,所以我們返回y:ys
= 5:[6, 7, 8]
= [5, 6, 7, 8]
。
請注意,我們總是有z == x
; 作為練習,嘗試處理一個示例輸入,其中這部分條件在計算過程中的某個時間點計算為假。
您可以使用任何類型的值作為foldr
的“累加器”參數,在這種情況下它是一個列表。 具體來說, foldr
具有以下類型:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
專門用於t
= []
因為輸入是一個列表,即:
foldr :: (a -> b -> b) -> b -> [a] -> b
在您的情況下,它進一步專門用於b
= [a]
因為output也是相同類型的列表:
foldr :: (a -> [a] -> [a]) -> [a] -> [a] -> [a]
a -> [a] -> [a]
參數用insx
填充,初始累加器是[x]
= [6]
,結果是 function [a] -> [a]
然后應用於輸入[5, 7, 8]
。 並且由於類型類約束, a
可以是集合Num
和Ord
中的任何類型,例如Int
或Integer
。
TDD 和逐步細化可以用來理解這個程序在做什么,如下所示:
insert' :: Ord a => a -> [a] -> [a]
f y [] = [y]
-- Follows to:
f y (z:[]) | (y <= z) = y : z : []
| otherwise = z : y : []
-- Follows to:
f y (z:zs) | (y <= z) = y : z : zs
| otherwise = z : y : zs
-- Follows to:
insert' y = foldr f [y]
where
f y ys@(z:zs) | (y <= z) = y : ys
| otherwise = z : y : zs
-- Follows to:
insert' x = foldr insx [x]
where
insx y ys@(z:zs) | z==x && x<y = z:y:zs
| otherwise = y:ys
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.