如何从未知构造函数的变量中提取值?
例如,我想否定Either中的值,如果构造为右:
let Right x = getValue
in Right (negate x)
此代码成功将Right的值(在本例中为Int)绑定到x。
这样可行,但是如果getValue返回一个Left呢?有没有办法确定let表达式中变量的类型?或者有更好的方法来解决这个问题吗?
答案 0 :(得分:18)
一般来说,你能做的是:
case getValue of
Right x -> Right $ negate x
e -> e
这应该是清楚的:它就像函数参数中的模式匹配,而不是值。为了做你需要的,你有一个默认情况下捕获任何不匹配的东西,然后返回它。
但是,在您的特定情况下,您可以做一些更好的事情:
negate `fmap` getValue
或者,使用import Control.Applicative
,您可以使用<$>
作为fmap
(negate <$> getValue
)的同义词。 fmap
函数的类型为fmap :: Functor f => (a -> b) -> f a -> f b
。对于任何仿函数 1 ,fmap
将普通值上的函数转换为仿函数中的函数。例如,列表是一个仿函数,对于列表,fmap = map
。在此处,Either e
代表一个仿函数,它是例外Left e
或值Right a
;将函数应用于Left
不会执行任何操作,但将函数应用于Right
会将其应用于Right
。换句话说,
instance Functor (Either e) where
fmap _ (Left l) = Left l
fmap f (Right r) = Right $ f r
因此,case
版本是您问题的直接答案,但您的特定示例更接近于fmap
。
1:初看起来,仿函数是“容器”。如果您对各种类型的课程不满意,我建议您the Typeclassopedia进行全面参考;还有更多的教程,感受它们的最好方法就是与它们一起玩。但是,特定类型的fmap
通常很容易使用(特别是在我看来,写<$>
时)。
答案 1 :(得分:2)
回答这个问题的标题:
我认为“... where
”和“let ... in ...
”之间没有太大区别。两者都允许您声明几个函数参数绑定案例:
f val = let negR (Right x) = Right (negate x)
negR y = y
in negR val
或
let { negR (Right x) = Right (negate x); negR y = y; } in negR val