【问题标题】:Haskell: Function application with $Haskell:使用 $ 的函数应用程序
【发布时间】:2011-12-04 21:15:23
【问题描述】:

在下面的 sn-p 中,你可以看到我在 Haskell 中编写的两个 collat​​z 函数。对于递归应用程序,我在第一个示例 (collat​​z) 中使用了括号来获得正确的优先级。

因为我刚刚学习了 $ 的函数应用程序,所以我尝试使用那个东西重写函数 (collat​​z')。但是,我遇到以下错误:

无法匹配预期类型“[a]” 针对推断类型 `a1 -> [a1]' 在 `(:)' 的第二个参数中,即 `collat​​z'' 在 `($)' 的第一个参数中,即 `n : collat​​z'' 在表达式中: n : collat​​z' $ n `div` 2

collatz :: (Integral a) => a -> [a]

collatz 1 = [1]

collatz n | even n    = n : collatz (n `div` 2)
          | otherwise = n : collatz (n * 3 + 1)

collatz' :: (Integral a) => a -> [a]

collatz' 1 = [1]

collatz' n | even n    = n : collatz' $ n `div` 2
           | otherwise = n : collatz' $ n * 3 + 1

这对我来说很奇怪,这不起作用。所以我尝试了一个类似的例子:

True : [even $ 3 `div` 3]

如果有人可以看看它并告诉我我做错了什么,我将不胜感激。

【问题讨论】:

  • 主题评论:让 collat​​z 函数只计算下一步(所以 collatz :: Integral => a -> a )然后使用类似 takeWhile (/= 1) . iterate 的东西在单独的步骤中构建列表可能是更简洁的代码跨度>
  • 虽然 $ 有时可以消除括号,但并非总是如此,有时使用括号更简洁。

标签: haskell ghci


【解决方案1】:

$ 的优先级低于:(以及其他任何内容),因此您的函数解析为

(n : collatz') $ (n `div` 2)

这会导致您的类型错误。 : 的第二个参数需要一个列表,但您传递的是 collat​​z 函数。

如果您仍然想避免 3n+1 部分周围的括号,您可以执行以下操作

(n:) . collatz' $ n `div` 2
n : (collatz' $ n `div` 2)

虽然这些不一定比原来的干净。如果您想知道,第一个示例中的(n:)\x -> n : x 的语法糖

【讨论】:

    【解决方案2】:

    既然其他人已经解释了问题所在,我想我会解释一下你是如何自己解决这个问题的。 (教人钓鱼等等……)

    注意这部分错误信息:

    在'($)'的第一个参数中,即'n : collat​​z''

    这是注意到这是一个优先问题的线索。 GHC 告诉您 n : collatz' 被解析为 $ 的第一个参数,而您期望第一个参数只是 collatz'

    此时,我通常会启动 GHCi 并使用 :info 命令检查涉及的优先级:

    > :info :
    data [] a = ... | a : [a]   -- Defined in GHC.Types
    infixr 5 :
    > :info $
    ($) :: (a -> b) -> a -> b   -- Defined in GHC.Base
    infixr 0 $
    

    它说: 的优先级是5,而$ 的优先级是0,这就解释了为什么:$ 绑定“更紧密”。

    【讨论】:

      【解决方案3】:

      : 的绑定比$ 更强。考虑

      Prelude> let f x = [x]
      Prelude> 1 : f 2
      [1,2]
      Prelude> 1 : f $ 2
      
      <interactive>:1:5:
          Couldn't match expected type `[a0]' with actual type `t0 -> [t0]'
          In the second argument of `(:)', namely `f'
          In the expression: 1 : f
          In the expression: 1 : f $ 2
      

      注意解析器找到的“表达式”1 : f;它看到的是(1 : f) $ 2 而不是1 : (f $ 2)

      【讨论】:

        【解决方案4】:

        正如@missingno 所说,这是一个运算符优先级问题。你可以这样重写它

        collatz' n | even n    = n : (collatz' $ n `div` 2)
                   | otherwise = n : (collatz' $ n * 3 + 1)
        

        但这显然对你没什么好处,因为你还有括号。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-02-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多