问题描述
在(原版)GHCi 8.6.5 中,以下功能完全有效:
f xs@ ~(x:xt) = xs
Suffix occurrence of @. For an as-pattern,remove the leading whitespace.
仅仅删除 @
和 ~
之间的空白似乎还不够,因为 @~
会被解释为运算符,所以我发现的唯一有效变体是
f xs@(~(x:xt)) = xs
我想知道以下内容,但在更改说明中找不到答案:
- 从 8.6.5 到 9.0.1 究竟发生了什么变化,导致了这种不兼容?
-
xs@(~(x:xt))
真的是编写此模式的最佳方式,还是有比此更好的方式?
解决方法
描述了 GHC 9.0 中 ~ 和 @ 处理的变化here。引用迁移指南:
GHC 9.0 实现了 Proposal 229,这意味着 !、~ 和 @ 字符对前后空格比以前更敏感。结果,一些过去以一种方式解析的东西现在会以不同的方式解析(或抛出解析错误)。
,添加括号 (variable@(~pattern)
) 是一个很好的解决方案。或者,您可以使用 let
或 where
绑定,或单独的惰性 case
:
-
rehead :: a -> [a] -> [a] rehead x' xs0 = x' : xs where _x : xs = xs0
-
rehead :: a -> [a] -> [a] rehead x' xs0 = let _x : xs = xs0 in x' : xs
-
{-# Language PatternGuards #-} rehead :: a -> [a] -> [a] rehead x' xs0 | let _x : xs = xs0 = x' : xs
如果你想在后续的守卫中使用这些绑定,这会非常有用。
-
rehead :: a -> [a] -> [a] rehead x' xs0 = case xs0 of ~(_x : xs) -> x' : xs
所有这些选项都是最大的懒惰:
head (rehead 5 [1,2])
- =
head (rehead 5 [])
- =
head (rehead 5 undefined)
- =
5
如果您使用 {-# Language Strict #-}
,那么您必须将 let
/where
绑定编写为 ~(_x : xs) = xs0
以允许 []
,以及列表参数绑定作为 ~xs0
允许 undefined
;要使用 case
获得 无可辩驳的 模式(不仅仅是懒惰),您必须编写 ~(~(_x : xs))
。