6

オプションの値にはリスト内包表記をよく使用します。

[Parent parent, Destination [DestPage currPage]] ++ [OpenChildren | parent == Bookmark 0]

しかし、オプションの値の代わりに選択を行う方法がわかりません。

私のコードの多くは次のようになります。

let lblTabX         = if isAtBottom then 5 else 3
    lblTabY         = if isAtBottom then 3 else 60
    lblTabPosition  = Position left (if isAtBottom then bottom else top)
    lblTabWidth     = if isAtBottom then lblPageX - 60 else 20
    lblTabHeight    = if isAtBottom then 20 else pageHeight - 80
    lblTabMargin    = if isAtBottom then Margin 0 3 else Margin 3 0

あなたがたくさんのifを見るように:)

だから私はいくつかの演算子で遊んでいて、この構文を思いつきました:

iif c l r = if c then l else r

infixl 8 <-/
(<-/) l c = iif c l

infixl 8 /->
(/->) = ($)

そして、前の例が今どのように見えるかが気に入っています:

let lblTabX         = 5 <-/ isAtBottom /-> 3
    lblTabY         = 3 <-/ isAtBottom /-> 60
    lblTabPosition  = Position left (bottom <-/ isAtBottom /-> top)
    lblTabWidth     = (lblPageX - 60) <-/ isAtBottom /-> 20
    lblTabHeight    = 20 <-/ isAtBottom /-> (pageHeight - 80)
    lblTabMargin    = Margin 0 3 <-/ isAtBottom /-> Margin 3 0

もちろん、これはおもちゃの例です。使う気はありません。しかし、私はただ興味がありました.if演算子以外に選択を表現する構文はありますか? 多分リスト内包表記で?

4

4 に答える 4

10

ifHaskell の 通常、よりエレガントな構文上の代替手段があるためです。あなたの例では、私は考えます

let (                lblTabX, lblTabY, lblTabPosition, lblTabWidth, lblTabHeight,    lblTabMargin )
     | isAtBottom =( 5,       3,       bottom,         lblPageX-60, 20,              Margin 0 3   )
     | otherwise  =( 3,       60,      top,            20,          pageHeight - 80, Margin 3 0   )

または、すでに部分的に評価されている演算子をローカルで定義することもできます。

let bottomCase/|/topCase | isAtBottom = bottomCase
                         | otherwise  = topCase
    lblTabY         =                      3 /|/ 60
    lblTabPosition  = Position left $ bottom /|/ top
    lblTabWidth     =        (lblPageX - 60) /|/ 20
    lblTabHeight    =                     20 /|/ (pageHeight - 80)
    lblTabMargin    =             Margin 0 3 /|/ Margin 3 0

何度もチェックしたくないのは確かですisAtBottom。使用する構文に関係なく、冗長なコードは常に悪いものです。しかし、単純なブール値に基づく 1 つの決定だけが必要な場合は、ifカスタム オペレーターを定義するのではなく、標準に固執します。

于 2013-10-29T10:42:57.483 に答える
5

おっと、それらすべての条件を取り除きます。あるコンテキストでは 1 つの値のセットを持ち、別のコンテキストでは別のセットを持つ一連の関連する設定があります。

data TabConfig = TabConfig { tabX, tabY, tabWidth, tabHeight :: Int,
                             tabPosition :: Position,
                             tabMargin :: Margin }

(レコード構文を使用する必要はありません。わかりやすくするために使用しています)

ここで、関数に適切な を提供する必要がありTabConfigます。そこから値を抽出できます。あなたは機能を提供することができますdefaultConfig...

defaultConfig :: Context -> TabConfig
defaultConfig c = TabConfig { 5, 3, 20, (pageHeight c) - 80,
                              Position left bottom, Margin 3 0 }

あなたも持つことができます

bottomConfig :: Context -> TabConfig
bottomConfig c = TabConfig { 3, 60, (pageX c) - 60, 20, Position left top, Margin 0 3 }

次に、適切なコンテキストで適切な TabConfig を提供するだけです。(うまくいけば、それContextが別のレコード スタイルのタイプであることがわかりました。もちろん、それで同じトリックをプレイできます)。

TabConfig にさらにパラメーターがあり、一番下にあるだけで一部が変更される場合は、次のことができます。

bottomConfig c = let def = defaultConfig c
                 in def { tabX = 3, tabY = 60, ...

現在のコンテキストに適した構成を構築し、関数で使用できるようにするだけです。テーブル描画関数は、ページ上の位置がサイズをどのように制限するかを決定するために使用するロジックについて知る必要があるのはなぜですか? 新しい条件が追加の制約を課すとどうなりますか? それらを混同するのは恐ろしいことです。関心の分離は、オブジェクト指向と少なくとも同じくらい関数型プログラミングにとって重要です。K

もちろん、私がほのめかそうとしているのは、あなたが Reader モナドを欲しているということです。しかし、Reader モナドは非常に単純なので、モナドがまだ難しければ、それを使っていることを意識する必要はありません。

于 2013-10-29T14:12:04.397 に答える
4

次の(?) GHC にData.Boolbool関数があります:

bool :: a -> a -> Bool -> a
bool f _ False = f
bool _ t True  = t

そして、あなたの例を書き直すことができます:

lblTabX = bool 3 5 isAtBottom
于 2013-10-29T08:16:54.447 に答える
0

パターン マッチングは選択のための主な構文であり、他のほとんどすべてはパターン マッチングで表現されます。(は、たとえばif同等の式で定義されます)。case

于 2013-10-29T10:42:21.563 に答える