Haskell:(++)和(:)运算符的求值顺序

cen*_*980 3 haskell functional-programming

我有以下Haskell表达式:

3 : [40] ++ [50] ++ 5 : [60]
Run Code Online (Sandbox Code Playgroud)

我想知道如何评估此表达式。哪个运算符具有更高的优先级,:或者++?我认为表达式的结果是[3,40,50,5,60],但是我通过以下方式做到了:

3 : [40] ++ [50] ++ 5 : [60]
3 : [40] ++ [50] ++ [5,60]
3 : [40] ++ [50,5,60]
3: [40,50,5,60]
[3,40,50,5,60]
Run Code Online (Sandbox Code Playgroud)

以上是评估表达式的正确方法吗?任何见解都表示赞赏。

Wil*_*sem 9

无论是(++) :: [a] -> [a] -> [a](:) :: a -> [a] -> [a]功能都5优先,因为我们可以在阅读哈斯克尔'10报告,并且是右关联。

我们也可以:ighcishell中使用以下数据:

Prelude> :i (:)
data [] a = ... | a : [a]       -- Defined in ‘GHC.Types’
infixr 5 :
Prelude> :i (++)
(++) :: [a] -> [a] -> [a]       -- Defined in ‘GHC.Base’
infixr 5 ++
Run Code Online (Sandbox Code Playgroud)

因此,这意味着:

3 : [40] ++ [50] ++ 5 : [60]
Run Code Online (Sandbox Code Playgroud)

的缩写:

3 : ([40] ++ ([50] ++ (5 : [60])))
Run Code Online (Sandbox Code Playgroud)

(++)运算符实现为

(++) :: [a] -> [a] -> [a]
(++) []     ys = ys
(++) (x:xs) ys = x : xs ++ ys
Run Code Online (Sandbox Code Playgroud)

(:)是一个数据构造,因此,这意味着它不能被“进一步评估”。

这是有道理的,因为这意味着它++仅在此处应用于尾巴,因此,只要我们对头部感兴趣,我们就不需要评估该函数。因此,尽管(++)右联想(++)会产生相同的列表,但通常比左联想便宜。

因此,如果我们要评估完整列表,则将其评估为:

   3 : ([40] ++ ([50] ++ (5 : [60])))
-> 3 : (40 : ([] ++ ([50] ++ (5 : [60]))))
-> 3 : (40 : ([50] ++ (5 : [60])))
-> 3 : (40 : (50 : ([] ++ (5 : [60]))))
-> 3 : (40 : (50 : (5 : [60])))
Run Code Online (Sandbox Code Playgroud)

或更详细:

   3 : ((40: []) ++ ((50 : []) ++ (5 : (60 : []))))
-> 3 : (40 : ([] ++ ((50 : []) ++ (5 : (60 : [])))))
-> 3 : (40 : ((50 : []) ++ (5 : (60 : []))))
-> 3 : (40 : (50 : ([] ++ (5 : (60 : [])))))
-> 3 : (40 : (50 : (5 : (60 : []))))
Run Code Online (Sandbox Code Playgroud)

  • 与严格的语言相比,Haskell似乎常常会颠倒评估顺序。通常首先对表达式的* outside *求值:`[50] ++([10] ++ [5])`的外部具有`[50] ++ _etc`,因此其求值为`50:( [10] ++ [5])`,然后是外部`(:)`,因为它是数据构造函数,因此您可以停止评估。您可以选择停止,也可以继续更深并结束于“ 50:10:5 = [50,10,5]”。在像Python这样的东西中,它会向后发生:`[50] ++([10] ++ [5])`->`[50] ++ [10,5]`->`[50,10,5 ]`,但这不是Python。 (3认同)