[英]Algebraic data type list into an actual list
我想創建一個函數,在其中輸入一個代數數據類型列表,它應該輸出一個實際列表。
例如,我們有一個list1 = P `Cons` (G `Cons` Empty)
輸出應為: [G,P]
我創建了以下代數數據類型:
data Elements = G | S | P deriving (Eq, Show)
data List a = Empty | Cons Elements (List Elements)
我當前的功能是:
list:: Elements -> [List]
list Empty = []
list Cons a (List b) = [a] ++ list (List b)
我在解決這個問題時遇到了麻煩,如果能得到一些幫助,我將不勝感激!
提前致謝!
讓我們從您的數據類型開始:
data Elements = G | S | P deriving (Eq, Show)
data List a = Empty | Cons Elements (List Elements)
從技術角度來看, Elements
沒有任何問題,但它是一個非常糟糕的名稱選擇。 正如其他人所指出的,命名類型Element
更為常見。 原因是你的數據類型聲明的英文翻譯是:
“元素”是黃金或白銀或鉑金。
什么時候說:
“元素”是金或銀或鉑金
此外,當您開始使用這種類型編寫代碼時,它會開始變得混亂。 如果您定義Elements
類型的值:
e :: Elements
e = P
這代表單個元素“白金”,而不是集合元素。 這種混淆可能會導致您使用錯誤的類型簽名編寫list
函數,因為您認為您是在說list
采用一堆Elements
,但類型簽名實際上表示list
只采用一個元素。
出於這個原因,我將搜索並替換您的所有代碼,我的其余答案將使用“ Element
”來討論這個版本:
data Element = G | S | P deriving (Eq, Show)
data List a = Empty | Cons Element (List Element)
list:: Element -> [List]
list Empty = []
list Cons a (List b) = [a] ++ list (List b)
list1 = P `Cons` (G `Cons` Empty)
繼續,您的List
類型有問題:
data List a = Empty | Cons Element (List Element)
您已經定義了一個參數化類型List a
,但是您還沒有在其定義中使用參數a
。 在您看到List a
定義的其他情況下,這是因為a
參數應該表示列表項的類型,因此可以使用相同的列表來保存Element
s 或Int
s 或其他任何內容。 由於您需要一個僅包含Element
的特殊列表數據類型,因此您應該編寫不帶參數的List
(在此聲明的左側和右側):
data List = Empty | Cons Element List
^^- no "a" ^^- no "Element" argument
現在,考慮list
的類型簽名:
list :: Element -> [List]
list
應該做的是獲取一個元素列表,例如:
list1 = P `Cons` (G `Cons` Empty)
並生成一個 Haskell 列表作為結果:
result1 = [G,P]
但是這個類型簽名說list
將采用單個Element
並生成一個 Haskell 列表,其項目是List
類型(即,一個自定義的Element
List
),換句話說,它將生成一個 List 的List
元素。 這肯定是不對的。
事實上, list
應該采用Element
的List
並返回Element
的(Haskell)列表,因此類型簽名應為:
list :: List -> [Element]
請注意,如果您僅將類型聲明加載到 GHCi 中並檢查示例參數和結果的類型:
ghci> data Element = G | S | P deriving (Eq, Show)
ghci> data List = Empty | Cons Element List
ghci> :type P `Cons` (G `Cons` Empty)
P `Cons` (G `Cons` Empty) :: List -- input is of type `List`
ghci> :type [G,P]
[G,P] :: [Element] -- output is of type `[Element]`
這將確認您需要一個函數List -> [Element]
。
現在,您的定義還有兩個錯誤:
list Cons a (List b) = [a] ++ list (List b)
像Cons a (List b)
這樣的模式需要用括號括起來以匹配單個參數,所以這應該是:
list (Cons a (List b)) = [a] ++ list (List b)
這里還有一個問題。 List
的使用在這里沒有意義。 List
是一種類型,它屬於類型簽名,而不屬於模式或表達式,至少不是這樣。 Haskell 已經知道Cons
的第二個字段是一個List
,所以你不需要告訴它。 您只需要將該字段分配給一個變量。 如果你從兩邊刪除List
:
list (Cons a b) = [a] ++ list b
最終定義應該進行類型檢查:
list :: List -> [Element]
list Empty = []
list (Cons a b) = [a] ++ list b
如果您想要倒序的結果,只需翻轉連接即可:
list :: List -> [Element]
list Empty = []
list (Cons a b) = list b ++ [a]
最終代碼:
data Element = G | S | P deriving (Eq, Show)
data List = Empty | Cons Element List deriving (Show)
list:: List -> [Element]
list Empty = []
list (Cons a b) = list b ++ [a]
list1 = P `Cons` (G `Cons` Empty)
main = print $ list list1 -- output [G,P]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.