Haskell:使用 $ 的函数应用

发布于 2024-12-19 23:44:35 字数 818 浏览 3 评论 0原文

在下面的代码片段中,您可以看到我用 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]

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

In the following snippet, you can see my two collatz functions I wrote in Haskell. For the recursive application I used parentheses in the first example (collatz) to get the right precedence.

As I have just learnt function application with $, I tried to rewrite the function (collatz') using that thing. However, I encounter the following error:

Couldn't match expected type `[a]'
against inferred type `a1 -> [a1]' In the second argument of `(:)', namely `collatz'' In the first argument of `($)', namely `n :
collatz'' In the expression: n : collatz' $ 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

It seamed weird to me that this didn't work. So I tried a similar example that worked:

True : [even $ 3 `div` 3]

I'd appreciate it, if somebody could take a look at it and tell me what I'm doing wrong.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蓦然回首 2024-12-26 23:44:35

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

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

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

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

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

尽管这些不一定比原来的更清晰。如果您想知道,第一个示例中的 (n:)\x ->; 的语法糖。 n:x

$ has lower precedence then : (and also anything else) so your function is parsing as

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

This leads to your type error. The second argument of : expects a list but you are passing the collatz function instead.

If you still want to avoid the parenthesis around the 3n+1 part you can do something like the following

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

although these are not necessarily cleaner then the original. In case you are wondering, the (n:) in the first example is a syntactic sugar for \x -> n : x

四叶草在未来唯美盛开 2024-12-26 23:44:35

既然其他人已经解释了问题是什么,我想我会解释一下你如何自己解决这个问题。 (授人以渔等等...)

注意错误消息的这一部分:

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

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

此时,我通常启动 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,这解释了为什么 :$ 绑定“更紧密”。

Since others have explained what the problem is, I figured I'll explain how you could have figured this out on your own. (Teaching a man to fish and so on...)

Note this part of the error message:

In the first argument of '($)', namely 'n : collatz''

That's the clue to noticing that this is a precedence problem. GHC is telling you that n : collatz' was parsed as the first argument of $, while you were expecting the first argument to be just collatz'.

At this point, I usually fire up GHCi and check the precedences involved using the :info command:

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

It says that the precendence of : is 5, while the precedence of $ is 0, which explains why the : is binding "tighter" than the $.

心在旅行 2024-12-26 23:44:35

: 的结合力比 $ 更强。考虑 注意

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)

: binds more strongly than $. Consider

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

Note the "expression" 1 : f found by the parser; it sees (1 : f) $ 2 rather than 1 : (f $ 2).

对你的占有欲 2024-12-26 23:44:35

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

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

但这显然不会给你带来太多好处,因为你仍然有括号。

As @missingno stated, it's an operator precedence problem. You could rewrite it like this

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

But that obviously doesn't buy you much, because you still have parenthesis.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文