所以我必须定义一个头函数的安全版本,当[]作为参数传递时不会抛出错误.这里是:
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x
Run Code Online (Sandbox Code Playgroud)
但是现在,这个功能还有用吗?因为假设类型"a"是Int,那么您可以添加两个Int类型的对象,但是您不能添加两个"Maybe Int"类型的对象.
"Just"就是这样一个功能.以下是如何使用其结果(对于ghci REPL):
import Data.Foldable (sequenceA_)
let writeLn = putStrLn . show
let supposedlyUnusable = writeLn <$> Just 0
sequenceA_ supposedlyUnusable
Run Code Online (Sandbox Code Playgroud)
打印1或我们可以继续尝试另一个有趣的例子 - 使用Nothing案例
let supposedlyUnusable = writeLn <$> Nothing
sequenceA_ supposedlyUnusable
Run Code Online (Sandbox Code Playgroud)
哪个不打印任何东西.
这是一个完整的程序,这对于其他情况下,即使工作Traversable或Foldable在那里你不能这样做的一个案例分析Maybe的价值.<$>是一个关键,它允许你将函数应用于Maybe或包含在任何内容中的任何内容Functor,如果你有两个Maybe(或两个相同的Applicative),你可以使用fn <$> applicative_a <*> applicative_b类似的模式,fn a b但在哪里a和b包含像Maybe值的东西.
因此,剩下几种方法可以使用Maybe我能想到的,所有这些都使用案例分析:
let {fn (Just n) = Just $ 1 + n; fn Nothing = Nothing}
fn v
-- but that was just a messy way of writing (1+) <$> v
Run Code Online (Sandbox Code Playgroud)
...
let fn v = case v of {Just n -> Just $ 1 + n; Nothing -> Nothing}
-- and that's the same program with a different syntax
Run Code Online (Sandbox Code Playgroud)
...
import Data.Maybe (fromMaybe)
fromMaybe someDefault v
-- and that extracted the `value` from `v` if we had `Just value` or else gave us `someDefault`
Run Code Online (Sandbox Code Playgroud)
...
let {fn (Just n) = writeLn n; fn Nothing = putStrLn "No answer"}
-- this one extracts an action but also provides an action when there's nothing
-- it can be done using <$> and fromMaybe instead, but beginners tend to
-- find it easier because of the tutorials that resulted from the history
-- of the base library's development
let fn v = fromMaybe (putStrLn "No answer") (writeLn <$> v)
Run Code Online (Sandbox Code Playgroud)
哦,哦!这个是neato:
import Control.Applicative
let v = Just 0 -- or Nothing, if you want
let errorcase = pure $ putStrLn "No answer"
let successcase = writeLn <$> v
sequenceA_ $ successcase <|> errorcase
-- that uses Alternative in which Maybe tries to give an answer preferring the earliest if it can
Run Code Online (Sandbox Code Playgroud)
当然我们也有经典:
maybe (putStrLn "No answer") writeLn v
Run Code Online (Sandbox Code Playgroud)
正如评论中提到的那样,你实际上可以添加两个Maybe.我只是想对此提出另一种观点.
是的,你不能直接适用(+)于Maybe IntS,但你可以升级到另一个功能,即能自动执行此操作.
要升级一元函数(比如(+1))你写fmap (+1) maybeInt或(+1) <$> maybeInt.如果(+1)有类型Int -> Int,则fmap (+1)表达式具有类型Maybe Int -> Maybe Int.
升级bin-or-more-ary函数在语法方面要复杂一些:(+) <$> maybeInt <*> maybeInt或者liftA2 (+) maybeInt maybeInt.同样,这里我们提倡(+) :: Int -> Int -> Int对liftA2 (+) :: Maybe Int -> Maybe Int -> Maybe Int.
Maybe以这种方式处理允许您构建一个与Maybe纯函数中的s 一起使用并推迟检查的计算Nothing.或者甚至避免这种情况,如果你最终将它插入另一个Maybe作为参数的函数.
当然,你可以使用fmap和使用liftA任何Applicative,而不仅仅是Maybe.