1

私は「RealWorldHaskell」(すばらしい本)を読んでいて、コンパイラがオーバーロードされた関数をどのように選択するかについて混乱しています。

型クラスがある場合

type JSONError = String

class JSON a where
    toJValue :: a -> JValue
    fromJValue :: JValue -> Either JSONError a

そしてこれらのような2つのインスタンス

instance JSON Bool where
    toJValue = JBool
    fromJValue (JBool b) = Right b
    fromJValue _ = Left "not a JSON boolean"

instance JSON String where
    toJValue = JString
    fromJValue (JString s) = Right s
    fromJValue _ = Left "not a JSON string"

コンパイラは、たとえば整数など、2つの「fromJValue」関数からどのように選択できますか?

4

2 に答える 2

6

式の一部として使用する場合fromJValue someValue、Haskell は式に必要な型を選択します。たとえば、次のようにします。

case fromJValue someValue of 
    Right str -> putStr str
    Left _ -> error

のインスタンスJSON Stringが選択されるputStrのは、文字列を取るためです。

必要な型を明確に判断できない場合は、「あいまいな型変数」エラーが発生し、型注釈を追加して、使用するインスタンスを手動で選択する必要があります。

どの種類のが含まれているかはまったく無関係であることに注意してくださいJValue someValue

于 2012-09-17T01:04:14.807 に答える
1

OO 言語では、オブジェクトを返すと、仮想メソッド テーブルが一緒に返されます。Haskell では、型クラスのメンバーを返す場合、辞書が隠しパラメーターとして渡されます。

したがって、実行時に問題はありません。非表示の辞書引数は、実装を取得するために VTable と同じように使用されます。

ここでの問題は、コンパイラが最初にインスタンスを選択する方法になります。

fromJValue使われている様子をご覧ください。

JSON データを含む文字列から始めて、解析関数に渡します。

foo :: String
foo = parseJsonString x

instance JSON Stringこれで、コンパイラは呼び出しチェーンに沿って辞書を渡す必要があることを認識します。

parseJsonString(正しい名前は覚えていません) 文字列を JSON データ型に解析します。何かのようなもの

data ParsedJSON = JBool Bool | JString string | JObject ...

parseJsonString :: JSON a => String -> Either JSONError a 

まず、渡された文字列をParsedJSONデータ構造に変換しようとします。

次に、構造体と、既に持っている辞書を に渡しfromJValueます。

xがの場合"{ foo : 222 }"、インスタンスはまだ であるためStringLeftブランチが呼び出され、パーサーは「JSON 文字列ではありません」と表示します。

もう 1 つのマイナーな点 - 本番環境では、意図を明確にするためにandの代わりにreturnand throwErrorfromを使用する必要がありました。しかし、それは単なるチュートリアル コードだと思います。MonadErrorLeftRight

于 2012-09-17T04:56:32.843 に答える