簡體   English   中英

Haskell-在函數和“where”語句中放置函數變量

[英]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 = 6foldr 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 = 8ys = [6]z = 6zs = [] 所以第一個守衛是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 = 7ys = [6, 8]z = 6zs = [8] 守衛評估為6 == 6 && 6 < 7再次為真,給出6:7:[8] = [6, 7, 8]

最后我們有insx 5 [6, 7, 8] 現在y = 5ys = [6, 7, 8]z = 6zs = [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可以是集合NumOrd中的任何類型,例如IntInteger

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM