2

私は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) に解析するように指示するにはどうすればよいですか。for のキャストを省略すると、parse x非網羅的なパターン エラーが発生します。これを変更すると、parse x :: a「コンテキスト (Parse a) からの 'parse' の使用から (Parse a1) を推測できませんでした」

parse "K" :: Piece ChessPieceHaskell に to to to(parse "k" :: ChessPiece, Black)を伝えるにはどうすればよい(King, Black)ですか?

4

3 に答える 3

3

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が行われる型は、コンテキストから決定されます。これは、パラメーター typeaです。

しかし何かを解析したいときは、GHC に結果の型を伝えるのに十分なコンテキストがなければなりません。典型的な番組では、それは通常、文脈から判断できます。特定の型を必要とするコンテキストでlet p = parse input後で使用すると、どの型を解析するかがコンパイラに通知されます。しかし、ghci プロンプトでは、そのようなコンテキストは存在せず、必要なタイプを ghci に明示的に伝える必要があります。pp

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のみ定義しました。もちろん、他の入力文字列の定義を提供する必要があります (無効な文字列を呼び出す明示的なキャッチオール ブランチを含む)。parse"k"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)

a定義のは新しい forall 量化型変数であり、ペアの最初のコンポーネントは任意のparseを持つことができると効果的に言います。

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

もちろん、instance Parse anyType文脈から推測できるものはありませんParse a

a拡張機能を使用して、タプル内の がインスタンス ヘッド内の型と同じ型を示す必要があることを GHC に伝えることができますがScopedTypeVariables、当面はそのままにしておくことをお勧めします。

于 2012-10-17T12:10:38.637 に答える
1

関数型でtypevariable を使用した場所ScopedTypeVariablesなどを使用できるようにするには、プラグマが必要です。parse x :: aa

FlexibleInstancesインスタンスを定義するためにPiece ChessPiece使用することもできPiece 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

于 2012-10-17T12:04:25.287 に答える
0

yourDraughtPieceは とほとんど同じなので、間違った単語であると思われるたびChessPieceに新しい型を発明しないのと同じ理由で、それらを同じデータ型に入れることをお勧めします。もう 1 つのボーナスは、ゲームの量を増やしたい場合に、コードのスケーリングが大幅に向上することです。MaybeNothing

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

ここで、データ表現を調整する必要があります。解析するファイルの表現を調整できる場合は、「ボード 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

最後の注意: 問題の主な問題は、データがアトミックに保存されていないためです。1 つのトークンには、図の色とタイプの両方に関する情報が含まれています。独自のファイルを設計するときは、別々のものを別々に保つようにしてください。

于 2012-10-17T12:14:01.440 に答える