6

私はHaskellで自分自身にスキームを書くことを経験しています。それは素晴らしいチュートリアルですが、構文解析の演習の1つで壁にぶつかりました:

parseNumber :: Parser LispVal
parseNumber = liftM (Number . read) $ many1 digit

以下を使用してparseNumberを書き換えます。

  1. 表記する
  2. >>=演算子を使用した明示的なシーケンス

do-notationに問題はありませんでした:

parseNumber :: Parser LispVal
parseNumber = do x <- many1 digit 
                 let y = read x
                 return $ Number y

#2については、次のようなバリエーションを試しました。

parseNumber :: Parser LispVal
parseNumber = (many1 digit) >>= (liftM (Number . read))

しかし、私はタイプエラーに遭遇し続けます。2つの質問があります。

  1. なぜタイプエラーが発生するのですか?モナディックバインド演算子を誤解していますか?
  2. do-notationソリューションで同様のタイプエラーが発生しないのはなぜですか?

タイプに関する基本的な概念が欠けているような気がしますか?

4

2 に答える 2

11

do-notationからbindnotationへの重要な変換を試みています。これを「簡単な」方法で実行し、ポイントフリーにすることをお勧めします。

想起:

x <-m === m >> = \ x->
 let x = e === let x = e in

次に、次のようになります。

parseNumber=many1桁>>=\ x->
               y=でxを読み取る
               return(Number y)

$(優先順位の問題を回避するためにを削除しました。)

次に、これを次のように変換できます。

parseNumber=many1桁>>=\ x-> return(Number(read x))
             =many1桁>>=return。番号 。読む

ここで、を使用する場合はliftM、bindの使用を停止する必要があります。これは、リフトされた関数が引数としてモナディック値を想定しているためです。

parseNumber =liftM(数値。読み取り)(多くの1桁)
于 2011-03-16T03:03:40.043 に答える
2

あなたの場合、bindのタイプは次のとおりです。

(>>=) :: Parser a -> (a -> Parser b) -> Parser b

Parserモナドとして使用しているため)

bindに2つの引数を指定します。最初の引数many1 digit、、は(タイプに関して)大丈夫である必要があります。しかし、2番目の引数の型はの結果型ですliftM。つまりParser a -> Parser b、これは2番目の引数の期待される型に適合しませ(a -> Parser b)

テストせずに:liftM (Number.read)bindの2番目の引数として使用する代わりに、使用してみてくださいreturn . Number . read-これは正しいタイプであり、おそらくあなたが望むものを与えるはずです...

于 2011-03-16T08:31:33.360 に答える