Haskell - 模式匹配句法糖和在哪里

时间:2012-01-19 19:51:58

标签: haskell

我常常具有这种模式的功能:

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一堆。 我可以使g成为一个单独的函数,但它并不好:我的模块命名空间将被实用程序函数污染。 有没有解决方法?

7 个答案:

答案 0 :(得分:10)

不,没有解决方法。如果您有类似函数的多个子句,则它们不能共享where - 子句。您唯一的选择是使用案例陈述,或执行以下操作:

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

...如果确实出于某种原因想要使用函数表单。

答案 1 :(得分:10)

我认为你的第一个例子根本不是坏事。唯一的句法权重是case x of,加上->而不是=;后者被您可以省略每个子句的函数名称这一事实所抵消。实际上,即使是dflemstr提出的go辅助函数在语法上也更重。

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

答案 2 :(得分:6)

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

答案 3 :(得分:5)

从Haskell 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
              ....

答案 4 :(得分:3)

您的原始解决方案似乎是最好的解决方法。从语法上来说,如果不是更轻,它就不会比函数参数上的直接模式匹配更重。

但是,如果您需要的只是检查先决条件而不是模式匹配,请不要忘记保护,这样您就可以自由地访问where范围。但实际上我在case of解决方案中没有看到任何不好的内容。

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

答案 5 :(得分:1)

假设您在案例陈述的大多数(如果不是全部)不同分支中始终使用g,这是否安全?

假设某些f :: a -> ba b(可能是多态的)gc -> d必然是c形式的某种函数,表示必须是一种从a中一致地提取getC :: a -> c的方法。称之为h . g . getC。在这种情况下,解决方案是在所有情况下使用h :: d -> bc

但是假设您无法始终从a中获取a。也许f c的格式为f,其中Functorfmap g :: f c -> f d?然后你可以f d,然后以某种方式将b转换为fmap

这里只是漫无目的,但当我看到你似乎在每个分支上都应用g时,{{1}}是第一个想到的东西。

答案 6 :(得分:1)

使用LambdaCase,您也可以执行此操作:

{-# language LambdaCase #-}

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