3

私は余暇に Haskell を勉強しており、最近はモナド関数の領域にも足を踏み入れています。私が抱えている正確な問題を特定するために、私が取り組んできた演習からコードを抽出して、この非常に不自然な例にしました。

import System.Random

rndPermu :: [a] -> IO (a, [a])
rndPermu xs = (front, back)
    where (front, back) = hurf xs

hurf :: [a] -> IO (a, [a])
hurf xs = randomRIO (0, (length xs) - 1) >>= \r -> return $ removeAt r xs

removeAt :: Int -> [a] -> (a, [a])
removeAt n xs = (e, rest)
    where e    = xs !! n
          rest = take n xs ++ (tail $ drop n xs)

rndPermu は GHCi にロードされたときに型エラーを生成し、型 (t, t1) が 'where' 句で予期されていたが、IO (a, [a]) が受信されたことを示します。(liftM fst) のようなものを使用して、タプルから個々の項目を取得し、単一の値を割り当てることができますが、それは明らかにずさんで回りくどい方法です。私はおそらく、目の前にある構文の小さなニュアンスにつまずいているように感じます。このタイプのエラーをどのように解決しますか? モナドでラップされたタプルに対して直接マッチできるはずですよね?

4

4 に答える 4

2

あなたが何をしようとしているのかを正しく理解している場合は、 のように から返されrndPermuた値を取り、そこからを削除しようとします。これは不可能です。モナドの戻り値は、関数が IO を使用し、呼び出しの結果を使用するすべての関数が間接的に IO を使用することを通知します。それらの戻り値もモナドにある必要があります。これは、型システムによって強制されます。IOhurfIOrndPermu :: IO a -> aIOhurfhurfIO

モナドでパターンマッチングを使いたいだけなら、最も直接的な方法は do 記法を使うことです:

rndPermu :: [a] -> IO (a, [a])
rndPermu xs =
   do (front, back) <- hurf xs
      return (front, back)

一般的なパターンは、さまざまな純粋な関数を使用して値をさらに処理することです。これらの関数は、IOまたは別のモナドから呼び出されるだけですが、それについて知る必要はありません:

-- pure function to do something with the result of |hurf|
modify :: (a, [a]) -> (a, [a])
modify (a, as) = (a, reverse as)

rndPermu :: [a] -> IO (a, [a])
rndPermu xs =
   do r <- hurf xs
      return (modify r)
-- or, with >>= operator:
-- hurf xs >>= return . modify
于 2009-12-28T19:37:06.440 に答える
2

なんで持ってないのかわからない

rndPermu xs = hurf xs

しかし、あなたが尋ねた質問に答えるには、これを試してください

rndPermu xs = do (front, back) <- hurf xs
                 return (front, back)

私の理解では、 内の何かを直接一致させることはできませんIO<-最初に構文を使用して抽出する必要があります。

于 2009-12-28T19:24:09.523 に答える
1

ブロックの代わりにdo、モナド値をバインドする関数でパターン マッチを行うことができます。

rndPermu xs = hurf xs >>= \(front, back) -> return (front, back)

rndPermu xs = hurf xs >>= \res -> case res of (front, back) -> return (front, back)
于 2009-12-29T14:14:08.560 に答える
0

あなたのコメントからの質問に答えるために、GHCirndPermuIO タイプを持つべきだと推測します。それは問題ではありません。問題は次の行です。

 where (front, back) = hurf xs

型推論とは、扱う式の型を指定する必要がないことを (大まかに) 意味するだけです。型推論は、Haskell が単純にある型の値を別の型に暗黙のうちに変換するという意味ではありません。実際にはまったく逆です。他の人が言ったように、したくない場合はブロックを書くdo必要はありませんが、IO値があるという事実に対処する必要があります。

于 2009-12-29T17:23:36.507 に答える