返回值的模式匹配

时间:2017-04-14 13:16:36

标签: haskell functional-programming pattern-matching tuples

我知道我可以使用模式匹配功能参数,如下所示:

fn :: (Integral a) => (a,a) -> (a, a)
fn (x,y) = (y,x)

但我如何匹配返回值?我希望这样的事情:

g :: (Integral a) => a -> a
g z = do
  (x, y) = fn (z, z + 5)
  x `mod` y

这会导致语法错误。有没有办法匹配返回值?基本上,我想将返回的元组拆分为两个变量。

2 个答案:

答案 0 :(得分:8)

do用于 monads 语法糖。但是你的功能不是单子。

您可以使用 let - 条款,例如:

g :: (Integral a) => a -> a
g z = let (x,y) = fn (z,(z+5)) in x `mod` y

where - 条款

g :: (Integral a) => a -> a
g z = x `mod` y
    where (x,y) = fn (z,(z+5))

您还可以在 lambda-expression 中定义模式,例如:

g :: (Integral a) => a -> a
g z = (\(x,y) -> x `mod` y) $ fn (z,(z+5))

沿着这些方向,您还可以定义执行模式匹配的辅助函数,例如:

g :: (Integral a) => a -> a
g z = h $ fn (z,(z+5))
    where h (x,y) = x `mod` y

如果需要以不同方式处理多个模式(例如Nothing类型的Just xMaybe a),这可能很有用。

比如说你定义了一个函数:

foo :: Int -> Int -> Maybe Int
foo x y | x > y = Just x
        | otherwise = Nothing

,您可以使用帮助函数bar定义qux来处理foo的输出,例如:

bar :: Int -> Int -> Int
bar x y = qux $ foo x y
    where qux Nothing = y
          qux (Just z) = z

最后,在2元组的情况下,您可以决定不使用模式匹配,但使用fst :: (a,b) -> asnd :: (a,b) -> b,例如:

g :: (Integral a) => a -> a
g z = let t = fn (z,(z+5)) in ( fst  t) `mod` (snd t)

但这不那么优雅,因为这里必须开始考虑fstsnd做什么,如果不进行优化,则会导致额外的计算开销。

选择哪一个当然取决于背景和个人品味。由于这里的模式是唯一的模式,我会选择letwhere模式,但就像法国人说的那样:“Lesgoûtsetles couleurs ne se discutent pas。

答案 1 :(得分:1)

在一般情况下,我个人的偏好是使用case .. of表达式。例如,如果f :: Int -> Maybe Int,我们可以写

g :: Int -> Int
g x = case f x of
   Nothing -> 5
   Just y  -> x+y

对于只有一个构造函数的类型,如元组,也可以使用let .. in

h a = let (x, y) = foo a in ...

但请记住,case是严格的,let是懒惰的。 E.g。

case undefined of (x,y) -> 5

引发错误。代替

let (x, y) = undefined in 5

评估为5。所以,它们并不完全等同。当使用无可辩驳的模式或匹配newtype构造函数时,它们变得如此。