【问题标题】:Haskell :: The Use of Brackets in RecursionHaskell :: 递归中括号的使用
【发布时间】:2017-09-12 16:41:34
【问题描述】:

我只是想知道,对于递归示例:

squaresRec :: [Double] -> [Double]   
squaresRec [] = []                       
squaresRec (x:xs) = x*x : squaresRec xs

为什么在递归的情况下,没有括号?不应该是这样的吗:

squaresRec :: [Double] -> [Double]   
squaresRec [] = []                       
squaresRec [x:xs] = x*x : squaresRec xs

我知道这行不通。但只是想知道它背后的解释。

【问题讨论】:

    标签: haskell recursion


    【解决方案1】:

    [] 匹配空列表。

    [1] 匹配一个只包含一个元素的列表,该元素必须是一个等于一的数字。请注意,[1] 实际上是 (1:[]) 的语法糖,也就是说,它真正匹配的是:一个以数字 1 开头的列表,然后是一个空列表……这只是表达“包含单个元素 1”的列表。

    (x:xs) 匹配以x 开头、后跟xs 的列表(可能包含任意数量的元素,可能为零)。 IE。此模式匹配具有至少一个元素的任何列表。

    [x:xs] 再次匹配包含恰好一个元素的列表,并且该元素应匹配模式(x:xs)。 (即使在类型方面也没有意义,因为您的列表包含Double-numbers,而不是列表。)

    【讨论】:

    • 我对 (1, 2, 3) 和 [1, 2, 3] 的使用感到困惑,我认为它代表一个元组和一个列表。我确实想过为什么不这样做[(x:xs)]?它是一个非空 [] 的列表,但有一个以 x 开头,其余为 xs 的列表。
    • 你可以写[(x:xs)],但括号在那里没有任何区别。一般来说,括号只影响代码解析的方式,但[...]已经将所有内容解析到一个AST节点中,所以不管你写[x:xs]还是[(x:xs)]甚至是类似于(([((((x):((xs)))))]))。方括号OTOH确实有所作为,即它们触发语法脱糖。 [x:xs](x:xs):[] 的糖,而 x:xs 已经脱糖。
    • 括号不是元组构造函数。他们在这里隔离了几个,(逗号),它们是真正的元组构建器
    • @Uniaika 这似乎不是一个特别有用的概念,因为元组的逗号在没有括号的情况下在任何地方都不会有效(而实际的建筑运算符会)。元组构造函数在语法上并不真正适合 Haskell 领域的其他任何东西,这可以说是它存在的原因(因为它比写 Tuple3 1 2 3 更好)
    【解决方案2】:

    我遇到了同样的问题,因为我来自 Erlang。

    要理解的是,我们在 Erlang 中的 [head|tail] 模式实际上是由 Haskell 中的 cons 函数翻译的,也就是 : 运算符。括号只是在这里隔离函数参数,就像 (3+4) 一样。

    我知道很容易问“为什么???”并且它在视觉上更有意义,但: 是我们构建(并在模式匹配时分离)链表的头部和尾部的方式。

    【讨论】:

    • 对很多人来说,它似乎确实具有“视觉意义”,但我一直不明白为什么。我发现写在方括号内的所有内容都是单个元素,而不是列表,这更加直观。特别是,我发现 [a b] 可以表示 a ++ b 的 Matlab 约定完全疯狂。
    • 嗯,Erlang 是我的第一门编程语言,所以我就是这样学习列表和列表理解的。对我来说,方括号表示列表的视觉上下文,您可以在其中执行诸如 cons 和列表推导之类的操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    相关资源
    最近更新 更多