[英]How to use custom version of List: `data List a = Nil | Cons a (List a)`?
這個問題基於 Graham Hutton第二版的“Haskell 編程”一書的“聲明類型和類”一章中的一個示例。
數據聲明為: data List a = Nil | Cons a (List a)
data List a = Nil | Cons a (List a)
使用此聲明的示例 function 是:
len :: List a -> Int
len Nil = 0
len (Cons _ xs) = 1 + len xs
但無論我嘗試了什么,我似乎都無法使用 function len
:
len Cons 1 Cons 2 Cons 3
len 1
len Cons
len (1)
len [1,2]
len Cons [1]
len (1,2)
len Cons (1,2)
len Cons 1 2
len (Cons (1,2))
len (Cons 1 2)
我錯過了len
和Cons
的任何排列嗎? 還是這個例子根本行不通?
您傳遞給len
的參數不是List
。 列表的末尾有Nil
,因此列表的形式為Nil
, Cons … Nil
, Cons … (Cons … Nil)
, Cons … (Cons … (Cons … Nil))
等。所以最終對於每個列表,結束列表的標記為Nil
。 Nil
等價於 Haskell 的[]
[a]
類型的 []。
此外,例如,您不能傳遞len Cons 1 Nil
,因為那時它將被解釋為((len Cons) 1) Nil
。 參數應該是一個列表。 通過使用括號,您可以將其寫為len (Cons 1 Nil)
。
對於給定的示例數據,您可以將其重寫為:
len Cons 1 Cons 2 Cons 3
len (Cons 1 (Cons 2 (Cons 3 Nil)))
len 1
len (Cons 1 Nil)
len Cons
len Nil
len (1)
len (Cons 1 Nil)
len [1,2]
len (Cons 1 (Cons 2 Nil))
len Cons [1]
len (Cons 1 Nil)
len (1,2)
len (Cons 1 (Cons 2 Nil))
len Cons (1,2)
len (Cons 1 (Cons 2 Nil))
len Cons 1 2
len (Cons 1 (Cons 2 Nil))
len (Cons (1,2))
len (Cons 1 (Cons 2 Nil))
len (Cons 1 2)
len (Cons 1 (Cons 2 Nil))
您還可以使用OverloadedLists
[haskell-doc]擴展來使用列表語法。 在這種情況下,您需要實現IsList
類型 class:
{-# LANGUAGE TypeFamilies #-}
import GHC.Exts(IsList(..))
data List a = Nil | Cons a (List a)
instance IsList (List a) where
type Item (List a) = a
toList Nil = []
toList (Cons x xs) = x : toList xs
fromList [] = Nil
fromList (x:xs) = Cons x (fromList xs)
如果您隨后啟用OverloadedLists
擴展,您可以將這些寫為列表文字:
{-# LANGUAGE OverloadedLists #-}
-- …
main = print (len [1,2])
您完全按照定義使用 function:
len Nil = 0
len (Cons _x xs) = 1 + len xs
然后,
list1 = Nil -- matches the first pattern
list2 = Cons 2 list1 -- matches the second pattern
list3 = Cons 3 list2 -- matches the second pattern
list4 = Cons 4 list3 -- matches the second pattern
等等等等。
手動寫出這樣的示例數據,我們需要使用括號來正確分組子術語以重新創建有效術語,例如
list5 = Cons 5 list4
= Cons 5 (Cons 4 list3)
= Cons 5 (Cons 4 (Cons 3 list2))
= ...
= Cons 5 (Cons 4 (Cons 3 (Cons 2 Nil)))
所有這些甚至都沒有查看數據類型定義。
當然,任何東西都可以用來代替1
、 2
等,只要它們都是相同的 type ,例如以下也是一個有效術語:
list54 = Cons list5 (Cons list4 Nil)
為什么? 由於數據類型定義,
data List a = Nil -- `Nil` constructs (is) a valid `List a` type term,
| -- OR,
Cons -- `Cons x xs` constructs (is) a valid `List a` type term, IF
a -- `x` is a valid term of type `a` , AND
(List a) -- `xs` is a valid term of type `List a`
Nil
構造(是)一個有效的List a
類型術語,而Cons x xs
構造(是)一個有效的List a
類型術語,如果x
是類型a
的有效術語並且xs
是類型List a
的有效術語,其中a
是一個和一個一樣。
因此,根據List a
數據類型定義,例如Cons 1 (Cons list2 Nil)
不是有效術語,即使 function len
似乎也可以處理它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.