簡體   English   中英

Haskell解析為自定義數據類型

[英]Haskell parsing to custom datatype

我是Haskell的新手。 這是我想做的:

我想將字符串解析為棋子。 我的代碼很簡單,所以我希望它能解釋一下自己:

data ChessPiece = King | ... etc
data DraughtPiece = DKing | ... etc
data Player = Black | White deriving (Show, Eq)
data Piece a = Piece (a, Player) 

因此,一個棋子可以是2個游戲中的任意一個,也可以是2個玩家中的任意一個。 我希望將字符串“ k”或“ K”分別解析為黑人或白人國王,所以我這樣做了:

class Parse a where
  parse :: String -> a

instance Parse ChessPiece where
  parse a = case a of 
    "k" -> King

到目前為止一切都很好..我可以調用> parse "k" :: ChessPiece 這可行!

instance Parse a => Parse (Piece a) where
   parse x | isLowercase x = Piece (parse             x, White)
           | otherwise     = Piece (parse $ lowercase x, Black)

這對任何一塊都必須起作用。 大寫和小寫的規則適用於DraughtPiece和ChessPiece。 我如何告訴Haskell將x解析為正確的類型(a)。 省略parse x會給我非窮盡的模式錯誤,將其更改為parse x :: a會給我“無法從上下文(分析a)的使用“分析”推斷出(分析a1)”

我如何告訴Haskell將parse "K" :: Piece ChessPiece (parse "k" :: ChessPiece, Black)(parse "k" :: ChessPiece, Black)(King, Black)

我如何告訴Haskell將x解析為正確的類型(a)。

如果您指的是

instance Parse a => Parse (Piece a) where
   parse x | isLowercase x = Piece (parse             x, White)
           | otherwise     = Piece (parse $ lowercase x, Black)

您不需要。 根據上下文確定進行遞歸parse的類型,它是參數類型a

但是,當您要解析任何內容時,必須有足夠的上下文來告訴GHC結果應具有哪種類型。 在典型的程序中,通常可以根據上下文確定。 如果let p = parse input ,然后在要求p具有某種類型的上下文中使用p ,則告訴編譯器應解析哪種類型。 但是在ghci提示符下,沒有這樣的上下文,您必須明確告訴ghci您想要哪種類型

ghci> parse "K" :: Piece ChessPiece

省略“ parse x”的類型轉換會給我非窮盡的模式錯誤,

如果您嘗試使用尚未顯式處理的輸入字符串來調用parse ,則會出現非窮舉的模式錯誤。 僅編譯會向您發出警告(如果您要求警告),例如

Pieces.hs:14:13: Warning:
    Pattern match(es) are non-exhaustive
    In a case alternative:
        Patterns not matched:
            []
            (GHC.Types.C# #x) : _ with #x `notElem` ['k']
            (GHC.Types.C# 'k') : (_ : _)

這意味着在instance Parse Piece ,您僅為單個輸入字符串"k"定義了parse 當然,您應該提供其他輸入字符串的定義(包括對無效字符串的明確的全包分支調用error )。

將其更改為'parse x :: a'使我'無法從上下文(Parse a)中使用'parse'來推斷(Parse a1)

這是一件不太明顯的事情。 類型變量是隱式的forall-quantified,因此在您編寫時

instance Parse a => Parse (Piece a) where
    parse x | isLowercase x = Piece (parse x :: a, White)

parse定義中的a是一個全新的forall量化類型變量,您實際上說這對的第一個組件可以具有任何類型,就像您說的那樣

instance Parse a => Parse (Piece a) where
    parse x | isLowercase x = Piece (parse x :: anyType, White)

當然,沒有可以從上下文Parse a推斷出的instance Parse anyType

您可以通過使用ScopedTypeVariables擴展告訴GHC,元組中的a應表示與實例頭中的a相同的類型,但最好暫時保留該類型。

您需要ScopedTypeVariables編譯指示來允許使用諸如parse x :: a類的東西,而您在函數類型中使用typevariable a parse x :: a地方。

如果您想為每種情況指定更具體的內容,也可以使用FlexibleInstances來為Piece ChessPiecePiece DraughtPiece定義實例。

instance Parse (Piece ChessPiece) where
   parse x = -- return Piece ChessPiece here 

instance Parse (Piece DraughtPiece) where
   parse x = -- return Piece DrauPiece here 

無論如何,ghc需要足夠的上下文來了解要解析的類型,因此您將需要parse "k" :: Piece ChessPiece類的東西parse "k" :: Piece ChessPiece

由於您的DraughtPiece幾乎是一樣的ChessPiece ,我建議你把它們放到出於同樣的原因,你沒有發明一種新的相同的數據類型Maybe鍵入每次都Nothing似乎是錯誤的單詞 另一個好處是,當您想增加游戲數量時,代碼的伸縮性要好得多。

data ChessPiece = King | ... etc
data Game = Game Int
data Player = Black | White
data Piece = Piece ChessPiece Player Game

現在,您必須調整數據表示。 如果可以調整要解析的文件的表示形式,則可以將“ black board of n”編碼為nk

import Data.Char

instance Parse Piece where
      parse x = case x of
            [n,p] | isLower p -> Piece (parse [p]) White (parse [n])
                  | otherwise -> Piece (parse [p]) Black (parse [n])
            _ -> [Parse error]

instance Parse ChessPiece where
      parse [p] = case toLower p of
            'k' -> King
            ...
            _ -> [Parse error]

instance Parse Game where
      parse = Game . digitToInt

最后一點:問題的主要困難是因為您的數據不是原子存儲的:一個令牌包含有關圖形的顏色和類型的信息。 在設計自己的文件時,請嘗試使單獨的內容分開。

暫無
暫無

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

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