11

次のHaskellコードでは:

data Cmd =  
    CmdExit |  
    CmdOther  
    deriving (Read, Show)

guiString2Cmd s =  
    (return (read s :: Cmd)) `catch` \(e :: SomeException) -> return CmdExit

私が行った場合:

guiString2Cmd "CmdOther"

それはすべて正常に動作します。しかし、私がそうする場合:

guiString2Cmd "some wrong string"

CmdExitに評価する代わりに、コードがクラッシュします。

クラッシュする代わりに、コードで例外を処理するにはどうすればよいですか?

4

4 に答える 4

13

reads合計である関数を使用し、次のMaybeように失敗ケースをとしてラップします。

maybeRead :: Read a => String -> Maybe a
maybeRead s = case reads s of
    [(x, "")] -> Just x
    _         -> Nothing

maybeRead安全な構文解析を行うための非常に用途の広い方法です。

于 2012-05-05T17:54:20.180 に答える
2

解決策は、代わりに読み取りを使用することです。

于 2012-05-05T08:17:36.070 に答える
2

私は個人的にパッケージreadMayから使用することをお勧めします:safe

readMay :: Read a => String -> Maybe a

次に、「多分」の結果でパターンマッチングを行うか、「多分」を使用するか、「多分」モナドを使用して結果を処理することができます。

于 2012-05-05T19:32:13.853 に答える
2

モナドの中に読むというイディオムがあります。

readM :: (Monad m, Read a) => String -> m a
readM s | [x] <- [x | (x, "") <- reads s] = return x
        -- or @[x] <- [x | (x, _) <- reads s] = return x@
        -- to allow the garbage at the end of parsed string
        | otherwise = fail $ "Failed to parse: \"" ++ s ++ "\""

IOモナドにとっては安全ではありません:

> readM "CmdOther" :: IO Cmd
CmdOther
> readM "Cmd?Other" :: IO Cmd
*** Exception: user error (Failed to parse: "Cmd?Other")

の場合は例外をfailスローしますが、これは処理できます。IOErrorIO

*Main> (readM "Cmd?Other" :: IO Cmd) `catch` const (return CmdOther)
CmdOther

そしてMaybeモナドの場合は安全です:

> readM "CmdOther" :: Maybe Cmd
Just CmdOther
> readM "Cmd?Other" :: Maybe Cmd
Nothing

この場合だからfailです。const Nothing

guiString2Cmdとにかく、署名付きのトータル関数が必要な場合は、次のString -> Cmdように記述できますreadM

guiString2Cmd :: String -> Cmd
guiString2Cmd s | [x] <- [x | (x, "") <- reads s] = x
                | otherwise = CmdExit

その後:

> guiString2Cmd "CmdOther"
CmdOther
> guiString2Cmd "Cmd?Other"
CmdExit

もう少し一般的なアプローチ。

*種類の場合:

class Failable0 t where
  fail0 :: t

readG0 :: (Failable0 t, Read t) => String -> t
readG0 s | [x] <- [x | (x, "") <- reads s] = x
         | otherwise = fail0

それから:

instance Failable0 Cmd where
  fail0 = CmdExit

* -> *種類の場合:

class Failable f where
  fail :: String -> f a

class Functor f => Pointed f where
  pure :: a -> f a

readG :: (Failable f, Pointed f, Read a) => String -> f a
readG s | [x] <- [x | (x, "") <- reads s] = pure x
        | otherwise = fail $ "Failed to parse: \"" ++ s ++ "\""
于 2012-05-06T06:56:36.260 に答える