从 Haskell 中的'Maybe a'返回类型中获取'a'值



我有一个Haskell函数eval :: WExp -> Memory -> WValue,它在不同的情况下有一堆不同的实例。目前,关于WExpMemoryWValue的知识还不相关。我的问题是,对于eval的一个特定实例,我使用的是lookup函数,该函数接受eval的参数(在本例中为字符串),搜索该字符串的键值对列表。注意,这个lookup函数不是前奏曲中包含的函数;它是在.hs文件中自行定义的。如果找到字符串,则返回与其关联的值,但如果找不到,则返回Nothing。由于Nothing的情况,lookup的类型实际上是Maybe a,其中在这种情况下a将是WValue。因为eval将返回一个Maybe WValue,所以编译器显然会抱怨该类型不是WValue

我认为可能有某种通用方法可以从任何返回Maybe a的函数中提取a值。

执行此操作

do
   input <- getUserInput
   result <- lookup input structure
   case result of
     Just a -> putStrLn $ "I'm so happy you chose "++show a++"."
     Nothing -> putStrLn $ "So sorry; "++input++" is not a valid option."

不要这样做

do
   input <- getUserInput
   result <- lookup input structure
   case result of
     Just a -> putStrLn $ "I'm so happy you chose "++show a++"."
     Nothing -> error $ input ++ " is not a valid option."

这很糟糕,因为如果用户输入错误,你的程序就会崩溃。

真的不要这么做

有一个名为fromJust的函数,它试图从Maybe中提取一个值,如果找到Nothing,就会抛出一个错误。看起来像

fromJust :: Maybe a -> a
fromJust (Just a) = a
fromJust Nothing = error "Oops, you goofed up, fool."

这让我们很难看出哪里出了问题。

真的,真的不要这样做

但是,如果你想玩火,你可以尝试一下,只是为了好玩。这将尝试从Maybe中获取一个值,如果找到Nothing,则会非常严重地崩溃。所谓"崩溃真的很难",我的意思是,如果你幸运的话,你会遇到分段错误,如果你不幸运,你会在网上发布你的私钥。

{-# LANGUAGE GADTs, DataKinds, KindSignatures #-}
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
module Unsafe.FromJust (unsafeFromJust) where
-- Clear sign of bad news
import Unsafe.Coerce (unsafeCoerce)
-- This creates a "closed kind" with types
-- 'JustType and 'NothingType. You could just
-- define datatypes called JustType and NothingType,
-- but this makes the intent clearer.
data MaybeType = JustType | NothingType
data M (t::MaybeType) a where
  -- The order of these constructors must not
  -- be changed, because this type must look,
  -- at runtime, exactly like a Maybe
  N :: M 'NothingType a
  J :: a -> M 'JustType a
-- A safe sort of fromJust for M.
fromJ :: M 'JustType a -> a
fromJ (J a) = a
-- Really, seriously unsafe.
unsafeFromJust :: Maybe a -> a
unsafeFromJust m = fromJ (unsafeCoerce m)

您要查找的函数是Prelude中定义的maybe

如果表达式为Nothing,则需要决定返回什么。假设您想要为Nothing获取空字符串""。然后下面的内容会让你走出"也许"框。

Prelude> maybe "" id (Just "hello")
"hello"
Prelude> maybe "" id (Nothing)
""

如果您知道查找成功,并且Maybe a实际上是Just a,那么您可以简单地进行模式匹配:

let (Just val) = lookup ...

你的Maybe a中有val::a。请注意,这是不安全的代码,如果lookup返回Nothing,它将不正常地抛出错误。

好吧,你让自己陷入了泥潭,因为你的lookup类型表明它可能会失败。在这种情况下,Haskell迫使您处理发生这种故障的可能性。如果lookup返回Nothing,则会出现这种情况。

如果你真的确信lookup从未失败(可能是因为你对程序进行了预处理和类型检查,或者你真的信任它:),你可以使用Data.Maybe中的fromJust。请注意,这实际上只是一个创可贴解决方案,因为如果使用Nothing调用fromJust,它将自己产生(Haskell)运行时错误。

最新更新