1

私は[Char]を持っています:

*Main> let message = "something"

そして、私は文字列をシャッフルしました(ここで見つけることができる完全なコード):

*Main> let key = shuffle message

*Main> message
"something"

*Main> :t message
message :: [Char]

*Main> key 
"goeimntsh"

*Main> :t key
key :: IO [Char]

次に、この 2 つの文字列から Data.Map を作成する必要があります。何かのようなもの:

Map.fromList(zip message key)

しかし、[Char] と IO [Char] を圧縮することさえできません。

*Main> zip message key
<interactive>:1:13:
    Couldn't match expected type `[b0]' with actual type `IO [Char]'
    In the second argument of `zip', namely `key'
    In the expression: zip message key
    In an equation for `it': it = zip message key

シャッフル関数は同じ入力に対して同じ結果を返さないことを理解しています。したがって、IO [Char] を返す必要があります。

Map.Map を取得できないことを理解し、IO Map.Map を取得することに同意します。しかし、通常の文字列と同じように IO [Char] を扱う必要があります。どうすれば入手できますか?

ありがとう。

更新しました:

皆様、ご説明ありがとうございます。追加の質問:

@ケニーTM:

「do」表記は理解できましたが、liftM を取得するには少し時間が必要です :) しかし、現在、追加の質問が 1 つあります。

*Main> let s = "abcdef"
*Main> let d = shuffle s
*Main> s
"abcdef"
*Main> d
"fedcba"
*Main> buildIOMap s d
fromList [('a','e'),('b','a'),('c','c'),('d','f'),('e','d'),('f','b')]
*Main> buildIOMap2 s d
fromList [('a','c'),('b','b'),('c','f'),('d','a'),('e','e'),('f','d')]
*Main> Map.fromList (zip "abcdef" "fedcba")
fromList [('a','f'),('b','e'),('c','d'),('d','c'),('e','b'),('f','a')]

「buildIOMap」は do 表記です。「buildIOMap2」 - liftM - 実現です。

3 つのケースで異なる結果が得られるのはなぜですか?

4

3 に答える 3

4

GHCiプロンプトから、あなたはただしなければなりません

> key <- shuffle message

これIOにより、右側でアクションが実行され、結果が に格納されkeyます。これは単なる文字列です。

> :t key
key :: [Char]

一方、あなたが書いたとき、

> let key = shuffle message

アクションに名前を付けるだけなので、たとえば、複数回実行して異なる結果を得ることができます。

> :t key
key :: IO [Char]
> key
"ntimshgoe"
> key
"gimhntoes"

値を評価することとアクションを実行することの違いは、同じプロンプトから両方を実行できるため、GHCi では多少あいまいです。ただし、例のように間違った方法で混合しようとすると、型エラーが発生しますzip

于 2012-10-30T06:53:29.010 に答える
3

このための IO 関数を作成できます。ここでは、命令型言語のバックグラウンドを持つ初心者にとってより使いやすい表記法を使用してdoいますが、最もコンパクトな方法ではありません。

buildIOMap message key = do
    rawKey <- key                   -- unwrap an object inside the 'do' with '<-'
    let zipped = zip message rawKey -- Then 'zip' & 'Map.fromList' can be used 
    let map = Map.fromList zipped   --   normally.
    return map                      -- Finally we re-wrap the result into IO.

関数自体を変換するという、より機能的な方法でこれを解決することもできます。式Map.fromList (zip message key)が失敗するのkeyは、IO [Char]が a ではなく であることに注意してください[Char]

関数Map.fromList (zip message __)を a の受け入れ[Char]から an の受け入れに変換できれば、IO [Char]それも機能します。このような変換は、 Haskell関数がこれを行う場合、 Liftingと呼ばれます。Control.Monad.liftM

liftM :: Monad m => (a -> r) -> (m a -> m r)

これは、1つの純粋な引数を持つ関数を取り、1つの純粋な引数を返し、1つのモナドの引数と1つのモナドの引数を返す関数を与えます。

ここで、純粋な関数は次のとおりです。

\x -> Map.fromList (zip message x)

したがって、次のようにも記述できます。

buildIOMap message = liftM (\x -> Map.fromList (zip message x))

(注: 上記を表すさらにコンパクトな方法はbuildIOMap message = liftM $ Map.fromList . zip message)

于 2012-10-30T06:32:45.027 に答える
3

keyは a ではありません[Char]- それは a ですIO [Char]- つまり a を返す IO 計算[Char]です。シャッフル機能の使用方法の例を次に示します。

main = do let message = "something"
          key <- shuffle message
          -- now key is a [Char]
          let m = Data.Map.fromList (zip message key)
          print m -- ... or whatever

ある意味では、はから を<-アンラップし、戻り値を の左側の変数に配置します。IOIO [Char]<-

于 2012-10-30T06:27:31.393 に答える