Haskell-模式匹配语法糖和where
我通常有这样一种模式的功能:Haskell-模式匹配语法糖和where,haskell,Haskell,我通常有这样一种模式的功能: f :: a -> b f x = case x of ... -> g ... ... -> g ... ... ... -> g ... where g = ... 几乎在这种情况下,有一种语法上的糖分: f :: a -> b f ... = g ... f ... = g ... ... f ... = g ... 不幸的是,我无法将我的附加到它的位置:我显然会得到一堆不在范围内的s。 我可以使g成为一个
f :: a -> b
f x = case x of
... -> g ...
... -> g ...
...
... -> g ...
where g = ...
几乎在这种情况下,有一种语法上的糖分:
f :: a -> b
f ... = g ...
f ... = g ...
...
f ... = g ...
不幸的是,我无法将我的附加到它的位置:我显然会得到一堆不在范围内的s。
我可以使g
成为一个单独的函数,但这并不好:我的模块的名称空间将被实用函数污染。
有解决办法吗?没有,没有解决办法。当这样的函数有多个子句时,它们不能共享where
-子句。您唯一的选择是使用case语句,或执行以下操作:
f x =
go x
where
go ... = g ...
go ... = g ...
g = ...
…如果出于某种原因您真的想使用函数形式。我认为您的第一个示例一点也不错。唯一的语法权重是
的案例x,加上->
,而不是=
;后者被以下事实所抵消:您可以省略每个子句的函数名。事实上,即使是dflemstr提出的go
helper函数在语法上也更重
诚然,与正常的function子句语法相比,它有点不一致,但这可能是一件好事:它在视觉上更精确地界定了x
可用的范围。您最初的解决方案似乎是最好的,也是唯一的解决方法。从语法上讲,它不比函数参数上的直接模式匹配更重,甚至更轻
f = g . h -- h is most of your original f
where h ... = ...
h ... = ...
g =
但万一您需要的只是检查前提条件而不是模式匹配,请不要忘记防护装置,它允许您自由访问where
范围。但实际上,我认为您的解决方案没有什么不好的地方
f :: a -> b
f a
| a == 2 = ...
| isThree a = ...
| a >= 4 = ...
| otherwise = ...
where isThree x = x == 3
从Haskell 2010开始,或通过GHC,您还可以:
f x
| m1 <- x = g
| m2 <- x = g
...
where g =
假设您在case语句的大多数(如果不是全部)不同分支上都一致地使用g
,是否安全
假设f::a->b
对于一些a
和b
(可能是多态的),g
必然是c->d
形式的函数,这意味着必须有一种方法从a
中一致地提取c
。称之为getC::a->c
。在这种情况下,解决方案是简单地使用h。GgetC
适用于所有情况,其中h::d->b
但是假设你不能总是从a
中得到c
。也许a
的形式是fc
,其中f
是函子
?然后您可以fmap g::fc->fd
,然后以某种方式将fd
转换为ab
这里有点杂乱无章,但是当我看到您似乎在每个分支上应用g
时,我首先想到的是fmap
。使用LambdaCase
,您也可以这样做:
{-# language LambdaCase #-}
f :: a -> b
f = \case
... -> g ...
... -> g ...
...
... -> g ...
where g = ...
用于定义函数的等式语法似乎是一种不必要的噱头。我认为OP是在寻找一个通用的解决方案,来解决g
可能出现在任何等式的RHS上的任何地方(或者根本不出现)的问题。是的,我觉得这个问题模棱两可,并给出了尚未回答的案例的答案。您不必导出g
,因此名称空间污染只是您自己模块中的一个问题。
{-# language LambdaCase #-}
f :: a -> b
f = \case
... -> g ...
... -> g ...
...
... -> g ...
where g = ...