簡體   English   中英

Haskell 實例 function

[英]Haskell instance function

我正在解決一本書中的一些練習,但現在我遇到了一些困難:在這個練習中,我將實現 Card 作為 class Ord 的一個實例。 但我不知道我該如何實施它,所以我將不勝感激任何幫助。

到目前為止,我的代碼如下所示:

data Suit = Diamond | Club | Spade | Heart

data Rank = Seven | Eight | Nine | Ten | Jack | Queen | King | Ace

data Card = Card Suit Rank

instance Ord Card where
 .... 

現在我不知道究竟如何實現這一點,我非常想了解它。 提前感謝您的解釋。

我無法想象練習實際上要您手動編寫必要的實例。 特別是對於SuitRank ,編寫它們會非常乏味(並且容易出錯)。

相反,您可能希望使用deriving關鍵字自動派生必要的實例。 如果你寫:

data Suit = Diamond | Heart | Spade | Club
  deriving (Eq, Ord)

這會自動派生EqOrd實例。 Ord實例需要Eq實例。)派生的Eq實例是不言自明的,派生的Ord實例使用構造函數在聲明中出現的順序,因此Diamond最小, Club最大。 如果您想要橋接訂單,請使用:

data Suit = Club | Diamond | Heart | Spade
  deriving (Eq, Ord)

反而。 相似地,

data Rank = Seven | Eight | Nine | Ten | Jack | Queen | King | Ace
  deriving (Eq, Ord)

Seven (最小)到Ace (最大)排序。 然后,如果你寫:

data Card = Card Rank Suit
  deriving (Eq, Ord)

派生實例根據第一個字段RankCards進行排序,並由Suit打破聯系。 如果你寫道:

data Card = Card Suit Rank
  deriving (Eq, Ord)

它會改為Suit排序,然后按Rank

一些代碼來說明:

data Suit = Diamond | Heart | Spade | Club
  deriving (Eq, Ord)

data Rank = Seven | Eight | Nine | Ten | Jack | Queen | King | Ace
  deriving (Eq, Ord)

data Card = Card Rank Suit
  deriving (Eq, Ord)

main = do
  let heart8 = Card Eight Heart
      spade8 = Card Eight Spade
      diamond7 = Card Seven Diamond

  print $ heart8 == heart8   -- True
  print $ heart8 == spade8   -- False
  print $ heart8 < spade8    -- True
  print $ diamond7 < spade8  -- True

我們可以向 GHCi 詢問有關Ord的信息。

:info Ord

這顯示了 class 定義,后跟實例列表。

type Ord :: * -> Constraint
class Eq a => Ord a where
  compare :: a -> a -> Ordering
  (<) :: a -> a -> Bool
  (<=) :: a -> a -> Bool
  (>) :: a -> a -> Bool
  (>=) :: a -> a -> Bool
  max :: a -> a -> a
  min :: a -> a -> a
  {-# MINIMAL compare | (<=) #-}
    -- Defined in ‘GHC.Classes’

它的超類是Eq:info Eq告訴我們:

type Eq :: * -> Constraint
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
  {-# MINIMAL (==) | (/=) #-}
    -- Defined in ‘GHC.Classes’

所以為了實現CardOrd ,我們需要兩件事:

  • instance Ord Card ,具有compare(<=)的定義
  • 具有(==)(/=)定義的instance Eq Card

由於這些實例編寫起來非常機械,通常我們要求編譯器自動派生它們:

data Suit = Diamond | Heart | Spade | Club
  deriving (Eq, Ord)

data Rank = Seven | Eight | Nine | Ten | Jack | Queen | King | Ace
  deriving (Eq, Ord)

data Card = Card Suit Rank
  deriving (Eq, Ord)

如果您將-ddump-deriv標志傳遞給 GHC,或在 GHCi 中使用:set -ddump-deriv ,它將打印出它為這些實例生成的代碼。

然而,任務是了解如何手動實現這些實例,所以讓我們 go 一步一步地完成它。

我們將從Eq開始。 對於SuitRank ,我們需要指定每個構造函數都等於其自身(也稱為自反性),而所有其他構造函數都不相等。

instance Eq Suit where
  Diamond == Diamond  = True
  Heart   == Heart    = True
  Spade   == Spade    = True
  Club    == Club     = True
  _       == _        = False

instance Eq Rank where
  Seven == Seven  = True
  Eight == Eight  = True
  Nine  == Nine   = True
  Ten   == Ten    = True
  Jack  == Jack   = True
  Queen == Queen  = True
  King  == King   = True
  Ace   == Ace    = True
  _     == _      = False

有了這個,我們可以通過對Card suit rank形式的值進行模式匹配,以類似的方式為Card定義==

instance Eq Card where

  -- Two cards are equal if…
  Card suit1 rank1 == Card suit2 rank2

    -- …their suits are equal,
    -- and their ranks are equal.
    = …

有兩種傳統的方法來定義主體。 一個是字面拼寫: suit1 == suit2 && rank1 == rank2 另一種是使用元組: (suit1, rank1) == (suit2, rank2)

同樣,要定義Ord ,我們可以從枚舉SuitRank的實例開始。 關於如何指定這些,我們有兩種選擇: (<=)compare 直接的選擇是只列出可能的案例表,我們可以縮寫案例:

instance Ord Suit where

  Diamond <= _        = True

  Heart   <= Diamond  = False
  Heart   <= _        = True

  Spade   <= Diamond  = False
  Spade   <= Heart    = False
  Spade   <= _        = True

  Club    <= Club     = True
  Club    <= _        = False

instance Ord Rank where

  …

對於Card ,我們現在只需要遵循與Eq相同的基本形式。 由於我們為SuitRank定義了(<=) ,請注意,我們會自動獲得其他比較函數的默認實現,例如這些類型的compare(<)

instance Ord Card where

  -- Two cards are in order if…
  Card suit1 rank1 <= Card suit2 rank2
    -- …one rank is less than the other,
    -- or their ranks are equal and suits are in order.
    = …

同樣,您可以使用(<)(||)(==)(&&)(<=)逐字翻譯此評論。

嘗試基於compare而不是(<=)來實現這些實例。 提示:使用Data.Ord中的comparinginstance Monoid Ordering

deriving (Enum)添加到RankSuit嘗試使用fromEnum來簡化它們的EqOrd定義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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