如何在Haskell中获得Maybe的"价值"

Moe*_*Moe 34 haskell return-value maybe

我对Haskell相对较新,并开始阅读"真实世界Haskell".我只是偶然发现了类型或许有一个关于如何从"Just 1"获得实际值的问题.我写了以下代码:

combine a b c = (eliminate a, eliminate b, eliminate c)
                where eliminate (Just a) = a
                      eliminate Nothing = 0
Run Code Online (Sandbox Code Playgroud)

如果我使用,这可以正常工作:

combine (Just 1) Nothing (Just 2)
Run Code Online (Sandbox Code Playgroud)

但是,如果我将1更改为String,则它不起作用.我想我知道为什么:因为Just 1必须回馈一种类型,在这种情况下,是一种类型eliminate.但是我怎么能改变Int至少与弦乐交易呢?(或者可能有各种类型?)

eph*_*ent 44

从标准来看Prelude,

maybe :: b -> (a -> b) -> Maybe a -> b
maybe n _ Nothing = n
maybe _ f (Just x) = f x
Run Code Online (Sandbox Code Playgroud)

给定默认值和函数,将函数应用于该值Maybe或返回默认值.

eliminate可以写maybe 0 id,例如应用身份功能,或返回0.

从标准来看Data.Maybe,

fromJust :: Maybe a -> a
fromJust Nothing = error "Maybe.fromJust: Nothing"
fromJust (Just x) = x
Run Code Online (Sandbox Code Playgroud)

这是一个部分函数(不会为每个输入返回一个值,而不是为函数返回值),但在可能的情况下提取值.

  • 而不是`也许',你也可以使用`Data.Maybe.fromMaybe :: a - >也许是 - > a` (7认同)

Dan*_*ton 23

[作者编辑,6年后]这是一个不必要的长答案,我不确定为什么它被接受了.使用maybeData.Maybe.fromMaybe按照最高评价答案的建议.接下来是更多的思想实验而不是实际建议.

因此,您正在尝试创建一个适用于许多不同类型的函数.这是上课的好时机.如果您使用Java或C++编程,Haskell中的类就像是这些语言中的接口.

class Nothingish a where
    nada :: a
Run Code Online (Sandbox Code Playgroud)

这个类定义了一个值nada,它应该是类的等价物Nothing.现在有趣的部分:制作这个类的实例!

instance Nothingish (Maybe a) where
    nada = Nothing
Run Code Online (Sandbox Code Playgroud)

对于类型的值,Maybe a类似Nothing的值是,嗯Nothing!这将在一分钟内成为一个奇怪的例子.但在此之前,让我们列出一个这个类的实例.

instance Nothingish [a] where
    nada = []
Run Code Online (Sandbox Code Playgroud)

空列表有点像Nothing,对吧?因此对于String(它是Char的列表),它将返回空字符串,"".

数字也很容易实现.你已经表明0显然代表了数字的"虚无".

instance (Num a) => Nothingish a where
    nada = 0
Run Code Online (Sandbox Code Playgroud)

除非您在文件顶部放置一个特殊行,否则这个实际上不起作用

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
Run Code Online (Sandbox Code Playgroud)

或者在编译它时,您可以设置这些语言编译指示的标志.不要担心他们,他们只是魔术,使更多的东西工作.

所以现在你已经有了这个类和它的这些实例......现在让我们重新编写你的函数来使用它们!

eliminate :: (Nothingish a) => Maybe a -> a
eliminate (Just a) = a
eliminate Nothing  = nada
Run Code Online (Sandbox Code Playgroud)

注意我只改变0nada,其余的都是一样的.让我们旋转吧!

ghci> eliminate (Just 2)
2
ghci> eliminate (Just "foo")
"foo"
ghci> eliminate (Just (Just 3))
Just 3
ghci> eliminate (Just Nothing)
Nothing
ghci> :t eliminate
eliminate :: (Nothingish t) => Maybe t -> t
ghci> eliminate Nothing
error! blah blah blah...**Ambiguous type variable**
Run Code Online (Sandbox Code Playgroud)

看起来非常适合价值观和东西.注意(Just Nothing)变成Nothing,看?这是一个奇怪的例子,一个可能在一个Maybe中.无论如何......怎么样eliminate Nothing?那么,结果类型是模糊的.它不知道我们期待什么.所以我们必须告诉它我们想要什么类型.

ghci> eliminate Nothing :: Int
0
Run Code Online (Sandbox Code Playgroud)

继续尝试其他类型; 你会看到nada每个人都有.所以现在,当你在combine函数中使用这个函数时,你会得到:

ghci> let combine a b c = (eliminate a, eliminate b, eliminate c)
ghci> combine (Just 2) (Just "foo") (Just (Just 3))
(2,"foo",Just 3)
ghci> combine (Just 2) Nothing (Just 4)
error! blah blah Ambiguous Type blah blah
Run Code Online (Sandbox Code Playgroud)

请注意,您仍然必须指出"Nothing"的类型,或指出您期望的返回类型.

ghci> combine (Just 2) (Nothing :: Maybe Int) (Just 4)
(2,0,4)
ghci> combine (Just 2) Nothing (Just 4) :: (Int, Int, Int)
(2,0,4)
Run Code Online (Sandbox Code Playgroud)

或者,您可以通过将其类型签名显式放入源中来限制函数允许的类型.如果函数的逻辑用法是仅用于相同类型的参数,则这是有意义的.

combine :: (Nothingish a) => Maybe a -> Maybe a -> Maybe a -> (a,a,a)
combine a b c = (eliminate a, eliminate b, eliminate c)
Run Code Online (Sandbox Code Playgroud)

现在它只有在所有三个可能的东西都是相同的类型时才有效.这样,它将推断出Nothing与其他类型相同的类型.

ghci> combine (Just 2) Nothing (Just 4)
(2,0,4)
Run Code Online (Sandbox Code Playgroud)

没有歧义,耶!但是现在混合和匹配是错误的,就像我们之前做的那样.

ghci> combine (Just 2) (Just "foo") (Just (Just 3))
error! blah blah  Couldn't match expected type  blah blah
blah blah blah    against inferred type         blah blah
Run Code Online (Sandbox Code Playgroud)

好吧,我认为这是一个足够长且过于夸张的答案.请享用.

  • 对于这样的初学者问题来说,这几乎肯定是错误的答案,过于复杂,而且*方式*先进.请不要教新手,简单的事情在Haskell中难以置信! (5认同)

Rob*_*rto 5

我也是 Haskell 的新手,所以我不知道这是否存在于平台中(我确信它存在),但是“get or else”函数如何获取一个值(如果存在),否则返回默认?

getOrElse::Maybe a -> a -> a
getOrElse (Just v) d = v
getOrElse Nothing d  = d
Run Code Online (Sandbox Code Playgroud)

  • `fromMaybe` http://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#v:fromMaybe (8认同)