【问题标题】:Application ($) operator acting unexpectedly应用程序 ($) 运算符意外动作
【发布时间】:2023-03-29 04:51:01
【问题描述】:

我正在编写一个基于起始数字生成 Collat​​z 链的函数,但我遇到了意外问题

代码如下:

-- original, works
collatzA :: Integer -> [Integer]
collatzA 1 = [1]
collatzA n
      | even n = n:collatzA (n `div` 2)
      | odd  n = n:collatzA (n * 3 + 1)

-- what I'm trying to do, won't compile, gives nasty errors
collatzB :: Integer -> [Integer]
collatzB 1 = [1]
collatzB n
      | even n = n:collatzB $  n `div` 2
      | odd  n = n:collatzB $  n * 3 + 1

-- attempted solution, works but re-adds the parentheses I tried to get rid of
collatzC :: Integer -> [Integer]
collatzC 1 = [1]
collatzC n
      | even n = n: (collatzC $  n `div` 2)
      | odd  n = n: (collatzC $  n * 3 + 1)

那么为什么collatzAcollatzC 有效,而collatzB 无效?

【问题讨论】:

    标签: haskell operators parameter-passing


    【解决方案1】:

    这个问题是由于运算符优先级或固定性

    例如(取自RWH,我强烈推荐)(+) 被声明为左关联,固定性为 6,(*) 被声明为左关联,固定性为 7。这意味着表达式

    8 + 7 + 6 * 5 * 4
    

    被解析为

    (8 + 7) + ((6 * 5) * 4)
    

    与您的示例类似,cons 运算符 (:) 是右关联的,具有固定性 5,而应用程序运算符 ($) 是右关联的,具有固定性 0。 由于($) 的固定性低于(:),因此对collatzB 的递归调用被(:)“抓取”

    n = (n:collatzB) $ (n `div` 2)
    

    This link 包含 Prelude 函数的固定信息,您也可以查看this post 了解更多信息。

    【讨论】:

      【解决方案2】:

      问题是f $ g 被编译器视为(f) $ (g)。如果您有f $ g $ h,编译器会将其视为(f) $ ((g) $ (h)),并且您通常可以扩展此模式。所以当你有

      n : collatzB $ n `div` 2`
      

      编译器认为这是

      (n : collatzB) $ (n `div` 2)
      

      (n : collatzB) 不进行类型检查。

      这是由于 $ 的固定性和它的右结合 (infixr)。


      如果括号对你有那么大的影响(他们不应该这样),你可以定义一个新的操作符为

      infixr 1 $:
      ($:) :: a -> (b -> [a]) -> b -> [a]
      a $: f = \x -> a : f x
      
      collatzB :: Integer -> [Integer]
      collatzB 1 = [1]
      collatzB n
          | even n = n $: collatzB $ n `div` 2
          | odd  n = n $: collatzB $ n * 3 + 1
      

      但老实说,这会导致更多的混乱而不是它的价值。我个人会坚持使用parens。

      【讨论】:

      • 非常聪明的解决方案;但我认为你是对的,它确实给校对人员带来了更多的困惑而不是帮助,所以我想我会听从你的建议并坚持括号
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-11
      相关资源
      最近更新 更多