我知道我可以使用模式匹配功能参数,如下所示:
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
这会导致语法错误。有没有办法匹配返回值?基本上,我想将返回的元组拆分为两个变量。
答案 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 x
和Maybe 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) -> a
和snd :: (a,b) -> b
,例如:
g :: (Integral a) => a -> a
g z = let t = fn (z,(z+5)) in ( fst t) `mod` (snd t)
但这不那么优雅,因为这里必须开始考虑fst
和snd
做什么,如果不进行优化,则会导致额外的计算开销。
选择哪一个当然取决于背景和个人品味。由于这里的模式是唯一的模式,我会选择let
或where
模式,但就像法国人说的那样:“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
构造函数时,它们变得如此。