簡體   English   中英

如何使用自定義版本的 List:`data List a = Nil | 缺點a(列表a)`?

[英]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)

我錯過了lenCons的任何排列嗎? 還是這個例子根本行不通?

您傳遞給len的參數不是List 列表的末尾有Nil ,因此列表的形式為NilCons … NilCons … (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 3len (Cons 1 (Cons 2 (Cons 3 Nil)))
  • len 1len (Cons 1 Nil)
  • len Conslen 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 2len (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)))

所有這些甚至都沒有查看數據類型定義。

當然,任何東西都可以用來代替12等,只要它們都是相同的 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.

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