2016-11-28 10 views
7

内部のガード私はLearn you a haskell本をつもりですし、第8章では、このハスケル - case文

data LockerState = Taken | Free deriving (Eq, Show) 
type Code = String 
type LockerMap = Map.Map Int (LockerState, Code) 

lookup' :: Int -> LockerMap -> Either String Code 
lookup' num_ map_ = 
    case (Map.lookup num_ map_) of 
     Nothing -> Left $ "LockerNumber doesn't exist!" 
     Just (state, code) -> if state == Taken 
           then Left $ "LockerNumber already taken!" 
           else Right $ code 

この作品のようなコードのスニペットがあります。

lookup' :: Int -> LockerMap -> Either String Code 
lookup' num_ map_ = 
    case (Map.lookup num_ map_) of 
     Nothing -> Left $ "LockerNumber doesn't exist!" 
     Just (state, code) -> 
     | state == Taken = Left $ "LockerNumber already taken!" 
     | otherwise = Right $ Code 

これはコンパイルされません。しかし、私はこのようなステートメントを守るためのif/elseブロックを変換したかったです。ハスケルでのガードの使用は非常に制限的/直観的ではないようです。 SO Ex1SO Ex2。どの場所で警備員を使うことができるかを私が読むことができる明確な情報源はありますか?

答えて

18

ガードが許可される場所は、関数定義とcaseの2つです。そう、

divide x y 
    | y == 0 = Nothing 
    -------- 
    | otherwise = Just (x/y) 
    ----------- 

positively mx = case mx of 
    Just x | x > 0 -> Just x 
     ------- 
    _ -> Nothing 

ガードは、単にパターンのための制約です:あなたは機能や->caseに支店に=を使用するので、両方のコンテキストでは、警備員はいつものように、後のパターンと前に体を見えますJust xは、Nothing以外の値と一致しますが、Just x | x > 0は、ラップされた値も正であるJustにのみ一致します。

私は決定的なリファレンスは、具体的には、警備員の構文を記述し、それらが許可されている場所を指定§ 3.13 CASE式と§ 4.4.3機能とパターンのバインディング、 Haskell Reportであると仮定します。あなたのコードで

は、あなたがしたい:

Just (state, code) 
    | state == Taken -> Left "LockerNumber already taken!" 
    | otherwise -> Right code 

これは単独のパターンで表現される:

Just (Taken, _) -> Left "LockerNumber already taken!" 
Just (_, code) -> Right code 
+1

グレート答え!特に「ガードは単にパターンの制約です」 – skgbanga