haskell 为什么单子不能被分解?

mfpqipee  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(107)

我不明白为什么我不能分解一个(比如说IO)单子。比如IO a -> a
我的问题起源于使用happstack并希望从(optional $ lookText "domain")返回的ServerPart (Maybe Text)中获取Text。然后我想起阅读到IO monad不能被转义。
我读过关于unsafePerformIO和它为什么不好的原因,但这些原因似乎都没有回答我的问题。

9lowa7mx

9lowa7mx1#

Monad s可以转义吗?

是的。这对于许多Monad非常容易,例如MaybeEither aState sIdentity等等。最常见的Monad被转义的函数之一是Monad(->) r。如果不能将函数转换为值,那么Haskell就没有什么用处了。

IO可以转义吗?

很不幸是的对于初学者来说,如果他们没有google一下,看到他们可以使用unsafePerformIO从技术上逃离IO,这会更好,正如你可能已经猜到的那样 * 不安全 。它不是用于普通代码,而是当你真正需要它时进入运行时系统的后门。首先,它用于实现一些较低级别的库,如Vector,但也用于与外部共享库(DLL)接口。 如果你不写这种代码,不要使用unsafePerformIO*。否则,您最终得到的代码将变得难以推理和维护,因为它绕过了类型系统。

如何逃离其他Monad s?

它从MonadMonad不等,但大多数monad transformers都有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

MaybeMonad有几种方法可以摆脱它:

> :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来了解它。然而,快速搜索使我在他们的网站上找到了这个例子,它看起来非常适用于您的情况。

deikduxw

deikduxw2#

让我用另一个问题来回答你的问题:为什么你认为你能从单子里得到东西

data Dud a = Dud

instance Functor Dud where
  fmap _ _ = Dud

instance Monad Dud where
  return _  = Dud
  Dud >>= _ = Dud

更直接地说,Monad使您能够 * 创建 * 和 * 合并 * 类型。这种形式存在许多类型,它们可能根本不允许您实际提取任何内容。
一个更有意义、更直接的例子是list monad。

returnList :: a -> [a]
returnList a = [a]

bindList :: [a] -> (a -> [b]) -> [b]
bindList as f = concat (map f as)

列表显然可以包含一些东西,但它们也可能失败。没有功能

[a] -> a

它在传递[]时不会抛出错误。
通常,您想要从monad中“得到一些东西”的原因是您有一个操作,

f :: a -> b

和一元值,如

m :: [a]

你想把这个a从单子中提取出来,并应用到你的函数中。如上所述,没有理由相信你能做到这一点。
相反,你做相反的事情--你把你的函数带到类型中!

map f :: [a] -> [b]

相关问题