我不明白为什么我不能分解一个(我们说IO)单子。如IO a -> a
?
我的问题起源于使用happstack并希望从(optional $ lookText "domain")
返回的ServerPart (Maybe Text)
中获得Text
。然后我想起读到IO
单子不能逃脱。
我读过unsafePerformIO
和它不好的原因,但这些原因似乎都不能回答我的问题。
Monad
s可以被转义吗?
是的。对于许多Monad
,如Maybe
、Either a
、State
、Identity
等,这非常容易。转义最常见的Monad
之一是函数Monad
: (->) r
。如果不能将函数转换为值,那么Haskell就不会有太多的优势了。
IO
可以转义吗?
不幸的是,是的。对于初学者来说,如果他们没有到处搜索并看到他们可以使用unsafePerformIO
从技术上逃离IO
,那将会好得多,正如您可能已经猜到的那样,不安全。它是而不是在正常代码中使用,而是在您真正需要它时进入运行时系统的后门。它主要用于实现一些较低级别的库,如Vector
,但也用于与外部共享库(dll)进行接口。如果你不写那种代码,不要使用unsafePerformIO
。否则,您最终会得到难以推理和维护的代码,因为它绕过了类型系统。
我们如何从其他Monad
s中逃脱?
它从Monad
到Monad
有所不同,但大多数单片变压器有run-
, eval-
或exec-
方法:
> :m Control.Monad.State
> runState (modify (*10) >> get >>= return . show) 1
("10", 10)
> :type runState (modify (*10) >> get >>= return . show) 1
runState (modify (*10) >> get >>= return . show) 1 :: (String, Int)
> evalState (modify (*10) >> get >>= return . show) 1
"10"
> execState (modify (*10) >> get >>= return . show) 1
10
Maybe
Monad
有几种逃脱方法:
> :m Data.Maybe
> maybe "nada" show (Just 2)
"2"
> maybe "nada" show Nothing
"nada"
> fromMaybe 1 (Just 10)
10
> fromMaybe 1 Nothing
1
> fromJust (Just 1)
1
> fromJust Nothing
*** Exception: Maybe.fromJust: Nothing
因此,正如您所看到的,并不是所有这些都可以安全使用。
这和Happstack有什么关系?
我不知道,我没有用过Happstack,所以不知道它。然而,快速搜索使我在他们的网站上找到了这个例子,看起来很适合你的情况。
让我用另一个问题来回答你的问题:为什么你认为你可以从单子中得到东西?
data Dud a = Dud
instance Functor Dud where
fmap _ _ = Dud
instance Monad Dud where
return _ = Dud
Dud >>= _ = Dud
更直接地说,Monad
使您能够创建和组合类型。这种形式存在许多类型,它们可能根本不允许您实际提取任何内容。
一个更有意义、更直接的例子是列表单子。
returnList :: a -> [a]
returnList a = [a]
bindList :: [a] -> (a -> [b]) -> [b]
bindList as f = concat (map f as)
列表显然可以包含内容,但它们也可能不包含内容。没有函数
[a] -> a
在传递[]
时不会抛出错误。
通常,你想从单子中"得到一些东西"的原因是你有一个像
这样的操作f :: a -> b
和像
这样的一元值m :: [a]
,您想将该a
从单子中取出并将其应用于您的函数。如上所述,没有理由相信你能做到。
相反,您将做相反的事情—将函数引入到类型中!
map f :: [a] -> [b]