7

私の人生で3回目は、Haskellを学ぼうとしています。今回は、 Learn youaHaskellを通じて...。
著者が警備員を説明するとき、彼はこの例を示します:

bmiTell :: (RealFloat a) => a -> String 
bmiTell bmi  
| bmi <= 18.5 = "You're underweight, you emo, you!"  
| bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"  
| bmi <= 30.0 = "You're fat! Lose some weight, fatty!"  
| otherwise   = "You're a whale, congratulations!"

と言います

これは、命令型言語の大きなifツリーを非常に彷彿とさせますが、これだけがはるかに優れており、読みやすくなっています。他の場合は木が通常眉をひそめている場合は大きいですが、問題が個別の方法で定義されているため、それらを回避できない場合があります。警備員はこれに対する非常に優れた代替手段です。

ガードの方が読みやすいのはわかりますが、その構文が「はるかに優れている」理由がわかりません
。より柔軟ですか?もっとパワフル?警備員の大きな利点は何ですか?

私の大きな問題はおそらく文です

他の場合は木が通常眉をひそめている場合は大きいですが、問題が個別の方法で定義されているため、それらを回避できない場合があります

誰かがその例を挙げられますか?

4

4 に答える 4

12

ドンはガードを使用する主な動機を与えますが、それに加えて、ガードはパターンマッチングとうまく組み合わされています。パターン上のすべてのガードが失敗した場合、次のパターンにドロップスルーするため、フォールスルーケースが重複することなく、パターンと状態を同時にチェックできます。これが(非常に人工的な)例です:

expandRange x (Just lo, Just hi) | hi < lo = (Just x, Just x)
expandRange x (Just lo, hi) | x < lo = (Just x, hi)
expandRange x (lo, Just hi) | x > hi = (lo, Just x)
expandRange _ range = range

制限がないと考える場合Nothing、これは比較する要素を取り、負の範囲をその要素のみに「拡張」するか、要素を含めるために下限/上限を移動するか、要素がすでに含まれている場合は範囲​​を変更しないままにします。

さて、ガードを使わずに上記をどのように書くかを考えてみましょう!パターンが異なるために、概念的に同じブランチを何回複製することになりますか?はい、この小さな例は問題を完全に回避するために書き直すことができると思いますが、それが常に可能(または望ましい)であるとは限りません。

ifこのスタイルの定義は、私の考えでは、ガードを使用して表現できる最も重要なことです。ガードを使用して表現すると、(ガードされていない)パターンのケースと表現の混合として記述された場合、恐ろしく冗長になり、読みにくくなります。 。

于 2012-10-09T15:20:19.027 に答える
7

ガードは構文的に次の点で軽量です。

  • 多くの異なるケース
  • ネストされたケース

比較:

describeLetter c
   | c >= 'a' && c <= 'z' = "Lower case"
   | c >= 'A' && c <= 'Z' = "Upper case"
   | otherwise            = "Not an ASCII letter"

と:

describeLetter c =
    if c >= 'a' && c <= 'z'
        then "Lower case"
        else if c >= 'A' && c <= 'Z'
            then "Upper case"
            else "Not an ASCII letter"

ルール部分は構文的に明確であり、保守が容易です。

さらに、それらはビューパターンとうまく構成され、心地よい構文を生み出します。

   f x | Just t <- bar x = Right (f t)
       | otherwise       = Left "some error case"

例えば。

于 2012-10-09T14:54:20.430 に答える
2

その場所の周りにたくさんの問題がある場合は、意思決定図として視覚化することができます。あなたが引用するLYAHの例の決定図の一部は次のようになります。

                 .
                / \
               /   \
              /bmi? \
              \     /
               \   /
             /  \ /  \
            /  /   \  \
           /   |   |   \
          /    |   |    \
         /     |   |     \
        /      |   |      \
< 18.5 /18.5-25|   | 25-30 \ > 30
      /        |   |        \
    ...       ... ...       ...

ガードの大きな利点は、構文の構造に決定図の構造を反映させることです。if-then-elseしかなかった場合は、一連のネストされたifを使用して上記の決定図を実装する必要があります。つまり、2ブランチの選択肢のカスケードを使用してマルチブランチの選択肢をエンコードする必要があります。アルゴリズムの高レベルのアイデアがわかりにくい場合は、ネストされます。

さて、LYAHの作者があなたが引用した文で得ていたと思うのは、ネストされたif-then-elseよりもガードを使用した方がうまくいかない場合があるということです。ただし、これは、選択肢が相互に依存している場合、つまり、意思決定図に多くのダイアモンドボックス(選択肢)が含まれ、それぞれに2つのブランチしかなく、他の方法で書き換えることができない場合にのみ当てはまります。bmiTellこの例では、BMIは4つのカテゴリにのみ分類でき、どちらも他のブランチと重複していないという点で、各ブランチは互いに独立していることに注意してください。

于 2012-10-09T15:12:47.913 に答える
0

警備員は視覚的にわかりやすく、冗長性が低く、「ノイズ」も少なくなります。

比較:

bmiTell bmi
 | bmi <= 18.5 = "................................."
 | bmi <= 25.0 = "..........................................."
 | bmi <= 30.0 = "...................................."
 | otherwise   = "................................"

bmiTell bmi =
 if       bmi <= 18.5 then "................................."
 else if  bmi <= 25.0 then "..........................................."
 else if  bmi <= 30.0 then "...................................."
 else                      "................................"

(さらに、CA McCannがフォールスルーケースについて言ったこと)。:)

于 2012-10-09T15:23:14.100 に答える