6

Haskell は初めてで、IO を正しく行う方法を理解しようとしています。

以下は正常に動作します:

main = do
  action <- cmdParser
  putStrLn "Username to add to the password manager:"
  username <- getLine
  case action of
    Add -> persist entry
      where
        entry = Entry username "somepassword"

次の結果はコンパイルエラーになります。

main = do
  action <- cmdParser
  case action of
    Add -> persist entry
      where
        entry = Entry promptUsername "somepassword"

promptUsername = do
  putStrLn "Username to add to the password manager:"
  username <- getLine

エラーは次のとおりです。

Couldn't match expected type `IO b0' with actual type `[Char]'
Expected type: IO b0
  Actual type: String
In the expression: username
[...]

ここで何が起こっているのですか?最初のバージョンは機能するのに、2 番目のバージョンは機能しないのはなぜですか?

Stack Overflow には、このような類似の質問がいくつかあることは知っていますが、この問題を説明しているようには見えませんでした。

4

2 に答える 2

9

usernameですがStringpromptUsernameですIO String。次のようなことをする必要があります:

username <- promptUsername
let entry = Entry username "somepassword"
persist entry
于 2012-08-18T06:33:51.463 に答える
0

別のバリエーションがあります。

main = do
  action <- cmdParser
  case action of
    Add -> do username <- promptUsername
              let entry = Entry username "somepassword"
              persist entry

promptUsername :: IO String
promptUsername = do
  putStrLn "Username to add to the password manager:"
  getLine

-- fake definitions to make things compile

persist :: Entry ->  IO ()
persist = print

cmdParser :: IO Add
cmdParser = fmap (const Add) getLine

data Add = Add deriving Show
data Entry = Entry String String deriving Show

問題は、それが文字列ではなくアクションpromptUsernameであるということです。アクション'は文字列'を返すため、型はですが、それ自体は文字列のようなものではありません。x位置にaが必要なため、アクションの形をしたものは、数値またはブール値よりもそこに収まりません。したがって、複雑なアクションを定義する際には、実行のいずれの場合でも、より単純なアクションから生じる文字列を「抽出」し、最初の引数としてエントリを指定する必要があります。次に、結果に対してアクションを実行しますIO StringEntry x yStringmainpromptUsernameStringpersistEntry

于 2012-08-18T12:09:03.570 に答える