[英]Inferring function type from function definition Haskell
因此,我正在接受有關Haskell的測試,一個問題說:
讓函數成為
lolo g x = ys
where ys = [x] ++ filter (curry g x) ys
然后確定稱為lolo的函數的類型。 選項包括:
a) (a,b) -> Bool -> b -> [(a,b)]
b) (b -> b -> b) -> Bool -> [b]
c) ((b,b) -> Bool) -> b -> [b]
d) (a -> b -> Bool) -> b -> [c]
有人可以解釋是哪一個,為什么嗎? 我對此很困惑...我不明白的是:
1)咖喱功能只能適用於功能嗎? 不是可能是元組的數據類型? 那么您可以推斷g在這種情況下是一個函數? 如果g和x都是函數怎么辦? 是否可以將咖喱與第n個參數一起使用? 我只看到咖喱與1個參數一起使用。
2)我不太了解的另一件事是ys定義的遞歸。 因此ys由ys定義,但在這種情況下我看不到基本情況。 它會永遠結束嗎? 也許是遞歸結束的過濾功能。
3)還在咖喱中gx =咖喱(gx)對嗎? (這是有關函數應用優先級的問題)
非常感謝
1) curry
的第一個參數必須是一個函數,這就是所謂的高階函數 ,它接受一個函數並返回一個新的函數。 雖然它的類型在GHCi中打印為
curry :: ((a, b) -> c) -> a -> b -> c
它更清楚地表示(IMO)為
curry :: ((a, b) -> c) -> (a -> b -> c)
顯然,它需要一個函數並返回一個新函數。 從技術上講,你可以說, curry
接受3個參數,類型之一(a, b) -> c
,類型的一個a
和類型之一b
。 它只需要一個通常接受參數元組的函數並將其轉換為帶有2個參數的函數。
2) ys
的計算將永遠不會結束,不必費心嘗試在其上調用length
,您將永遠運行該計算。 不過,這不是問題,您可以使用無限列表和非終止列表就可以了(非終止是永遠需要計算下一個元素的列表,而不僅僅是具有無限元素的列表)。 不過,您仍然可以使用諸如“ take
drop
功能。
3) curry gx == curry (gx)
嗎? 沒有! 當您看到類似abcde
的表達式時, b
, c
, d
和e
都是a
參數。 如果改為看到abc (de)
,則將e
應用於d
,並將結果應用於abc
。 考慮filter even [1..10]
,這肯定與filter (even [1..10])
,因為它甚至不會編譯! ( even :: Integral a => a -> Bool
)。
解決此類問題時,首先查看您已經知道以下類型的表達式中使用了哪些函數:
(++) :: [a] -> [a] -> [a]
filter :: (b -> Bool) -> [b] -> [b]
curry :: ((c, d) -> e) -> c -> d -> e
我在每個變量中使用了不同的類型變量,以便在嘗試排列類型時會減少混亂。 您可以通過加載GHCi然后輸入以下內容來獲取這些類型
> :type (++)
(++) :: [a] -> [a] -> [a]
> -- Or just use :t
> :t filter
filter :: (a -> Bool) -> [a] -> [a]
> :t curry
curry :: ((a, b) -> c) -> a -> b -> c
如您所見,我將filter
更改為使用b
而不是a
,將curry
更改為使用c
, d
和e
。 除了fx = x + 1
相對於fy = y + 1
,這並沒有改變含義,只會使討論變得更容易。
現在我們已經將功能分解為子組件,我們可以從上至下進行工作。 最重要的是,我指的是最后一個被調用的函數,即(++)
。 您可以通過像這樣的樹來描繪此功能
(++)
/ \
[x] filter
/ \
curry ys
/ \
g x
因此,我們可以清楚地看到(++)
在頂部。 利用這一點,我們可以推斷, [x]
具有式[a]
這意味着x ~ a
(波浪號的類型是平等符號)並且因此ys ~ [a]
中,由於ys = [x] ++ something
。 現在我們知道了x
的類型,我們可以開始填寫其余的表達式了。 接下來,我們努力filter (curry gx) ys
。 由於它是(++)
的第二個參數,因此我們可以推斷出該子表達式也具有[a]
類型。 如果我們看一下filter
的類型:
filter :: (b -> Bool) -> [b] -> [b]
最終結果是[b]
類型的列表。 由於已將其應用於[x] ++
,因此我們可以推斷出該filter (curry gx) ys :: [a]
。 這意味着[b] ~ [a] => b ~ a
。 供參考,這使filter
的類型
filter :: (a -> Bool) -> [a] -> [a]
現在,這對curry gx
了約束,它必須適合filter
的第一個參數,其類型a -> Bool
。 再次查看curry
的類型:
curry :: ((c, d) -> e) -> c -> d -> e
這意味着, e ~ Bool
,和d ~ a
。 如果我們重新插入
curry :: ((c, a) -> Bool) -> c -> a -> Bool
現在忽略g
,我們看一下x
的類型,我們發現它是a
。 因為x
是第二個參數curry
,這意味着, x
型的參數匹配c
,這意味着c ~ a
。 將其代入我們剛剛計算出的結果
curry :: ((a, a) -> Bool) -> a -> a -> Bool
用
curry g x :: a -> Bool
filter (curry g x) :: [a] -> [a]
filter (curry g x) ys :: [a]
[x] ++ filter (curry g x) ys :: [a]
由此我們可以直接推斷出lolo
的類型簽名以[a]
結尾,因此
lolo :: ??? -> [a]
我將讓您執行其余的步驟來弄清楚是什么???
是。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.