2012-01-19 33 views
17

我经常有这样的模式的功能:哈斯克尔 - 模式匹配的语法糖和地方

f :: a -> b 
f x = case x of 
    ... -> g ... 
    ... -> g ... 
    ... 
    ... -> g ... 
    where g = ... 

没有为几乎这种情况下的语法糖:

f :: a -> b 
f ... = g ... 
f ... = g ... 
... 
f ... = g ... 

不幸的是,我可以”不要把我的where附加到它上面:我显然会得到一堆not in scope s。 我可以使g成为一个单独的函数,但这并不好:我的模块的名称空间将被实用程序函数污染。 有什么解决方法吗?

+4

您不必出口'g',因此命名空间的污染只是一个问题* *内自己的模块。 –

回答

10

我认为你的第一个例子并不糟糕。唯一的语法权重是case x of,加上->而不是=;后者由于可以省略每个子句的函数名称而被抵消了。事实上,即使dflemstr提出的go辅助函数在语法上也较重。

不可否认,它与普通函数子句语法相比稍有不一致,但这可能是一件好事:它更直观地界定了x可用的范围。

+0

用于定义函数的等式语法看起来像是一种不必要的噱头。 –

10

不,没有解决方法。当你有这样一个功能的多个子句时,他们不能共享一个where条款。你唯一的选择是使用一个case语句,或做这样的事情:

f x = 
    go x 
    where 
    go ... = g ... 
    go ... = g ... 
    g = ... 

...如果你真的使用函数形式,出于某种原因。

6
f = g . h -- h is most of your original f 
    where h ... = ... 
     h ... = ... 
     g = 
+0

我认为OP正在寻找一个通用的解决方案,其中'g'可能出现在任何方程的RHS上的任何地方(或根本不存在)。 –

+1

是的,我觉得这个问题很模糊,给出了一个还没有得到答案的答案。 – dave4420

3

您的原始解决方案似乎是最好的和唯一的解决方法。从语法上讲,如果功能参数更轻,则不会比直接模式匹配更重。

但是,如果你需要的只是检查先决条件而不是模式匹配,请不要忘记守卫,它允许你自由访问where范围。但我真的没有看到你的case of解决方案没有什么不好。

f :: a -> b 
f a 
    | a == 2 = ... 
    | isThree a = ... 
    | a >= 4 = ... 
    | otherwise = ... 
    where isThree x = x == 3 
5

从2010年哈斯克尔上,或者用GHC你也可以这样做:

f x 
    | m1 <- x = g 
    | m2 <- x = g 
    ... 
    where g = 

但请注意,您不能使用g的模式绑定的变量。这相当于:

f x = let g = ... in case() of 
    () -> case x of 
      m1 -> g 
      _ -> case x of 
       m2 -> g 
       .... 
1

它是安全的假设你一直使用的最g,如果不是全部,case语句的不同分支的?

在假设f :: a -> b一些ab(可能多晶型),g是一定形式c -> d,这意味着有必须是一种方法,持续提取ca的一些功能操作。打电话给getC :: a -> c。在这种情况下,解决方案将仅针对所有情况使用h . g . getC,其中h :: d -> b

但是,假设你不能总是从a得到c。也许a的形式是f c,其中fFunctor?然后你可以fmap g :: f c -> f d,然后以某种方式将f d转换成b

只是在这里漫步,但fmap是当我看到你似乎在每个分支上应用g时想到的第一件事。

0

随着LambdaCase,你也可以这样做:

{-# language LambdaCase #-} 

f :: a -> b 
f = \case 
    ... -> g ... 
    ... -> g ... 
    ... 
    ... -> g ... 
    where g = ...