【问题标题】:Ternary operator in haskellHaskell中的三元运算符
【发布时间】:2013-10-29 07:11:31
【问题描述】:

我经常对可选值使用列表推导:

[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

正如你看到的很多如果:)

所以我在玩一些运算符并想出了这个语法:

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 运算符之外,还有表达选择的语法吗?也许有列表推导?

【问题讨论】:

  • 嗯,iif isAtBottom 5 3 看起来比 5 &lt;-/ isAtBottom /-&gt; 3 更简洁
  • 顺便说一句,Haskell 的 if ... then ... elseexact 等效于类 C 语言中的三元 ? : 运算符(不是“the 三元运算符”,它恰好是这些语言中唯一存在的三元运算符。原则上,可能有很多其他三元运算符与 ifthenelse 决策无关)。
  • 严格来说,到目前为止你得到的所有答案都在回答你的问题,但它们并没有给你一个好的答案。您根本不应该将所有这些条件混合在一起。将这些设置移动到某种配置对象中,为上下文构建适当的配置(例如,默认、atBottom、atTop、atLeft、atRight)并将该配置提供给您的表格绘图/操作函数。
  • 你是如何在 Haskell 中开发 web 的?

标签: haskell list-comprehension ternary-operator


【解决方案1】:

Haskell 中的ifs 不是很漂亮,但这并不是它们很少使用的真正原因。这更多是因为通常有更优雅的语法替代方案!在你的例子中,我会考虑

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,无论您使用哪种语法,冗余代码总是不好的。 但是,当您确实需要基于简单布尔值的单一决策时,我会坚持使用标准 if,而不是定义自定义运算符。

【讨论】:

    【解决方案2】:

    Data.Bool 的 next(?) GHC 中,我们将有一个 bool 函数:

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

    我们可以重写你的例子:

    lblTabX = bool 3 5 isAtBottom
    

    【讨论】:

    • 这是一种有用的技术,其中有一个简单的可选值。如果有许多相关值并且它们都测试相同的条件,那是不够的。更糟糕的是,如果有多个条件,一些与值的一个子集相关,另一些与另一个相关,可能有一些重叠。
    【解决方案3】:

    哇,摆脱所有这些条件。你有一堆相关的设置,在一个上下文中会有一组值,在另一个上下文中会有另一组值。

    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。 (Hopefull,你发现Context 是另一种唱片风格的类型,当然你可以用它玩同样的把戏)。

    如果 TabConfig 有更多参数并且在底部只改变了一些,你可以这样做

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

    只需为当前上下文构建正确的配置并使其可用于您的函数。为什么你的表格绘图函数必须知道你用来决定它们在页面上的位置如何限制它们的尺寸的逻辑?当新的条件施加额外的限制时会发生什么?把它们混在一起太可怕了。关注点分离对于函数式编程至少与 OO 中一样重要。克

    当然,我想暗示的是你想要 Reader monad。但是 Reader monad 非常简单,如果 monad 仍然让您望而生畏,您不必知道自己正在使用它。

    【讨论】:

      【解决方案4】:

      模式匹配是选择的主要语法,大多数其他的东西都是用它来表达的。 (例如,if 是根据等效的 case 表达式定义的)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-06
        • 2021-08-01
        • 2018-09-10
        • 2017-03-09
        相关资源
        最近更新 更多