是否有带签名:: (Monad m) => m a -> a
的内置函数?
Hoogle告诉我们没有这样的功能。
你能解释一下原因吗?
答案 0 :(得分:44)
monad只提供两个功能:
return :: Monad m => a -> m a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
这两个都返回m a
类型的东西,因此无法以任何方式组合这些以获得类型Monad m => m a -> a
的函数。要做到这一点,您需要的不仅仅是这两个功能,因此您需要了解有关m
的更多信息而不是它的monad。
例如,Identity
monad具有runIdentity :: Identity a -> a
,并且几个monad具有相似的功能,但是无法一般地提供它。事实上,无法逃脱"来自monad对于像IO
这样的monad来说是必不可少的。
答案 1 :(得分:22)
可能有一个比这更好的答案,但是一种方法可以看出为什么你不能有一个类型(Monad m) => m a -> a
是考虑一个空monad:
data Null a = Null
instance Monad Null where
return a = Null
ma >>= f = Null
现在(Monad m) => m a -> a
表示Null a -> a
,即无中生有。你不能这样做。
答案 2 :(得分:14)
这不存在,因为Monad
是组合的模式,而不是分解的模式。您可以随时将更多部分与其定义的界面放在一起。它没有说要分开任何东西。
问你为什么不能拿出一些东西就像问为什么Java的Iterator
接口不包含一个方法来添加迭代的元素。它不是Iterator
接口的用途。
关于具有某种提取函数的特定类型的论证遵循完全相同的方式。 Iterator
的某些特定实现可能具有add
功能。但由于它不是Iterator
的用途,因此某种特定实例上的方法存在无关紧要。
fromJust
的存在同样无关紧要。这不是Monad
旨在描述的行为的一部分。其他人提供了许多类型的例子,其中extract
没有价值。但是那些类型仍然支持Monad
的预期语义。这个很重要。这意味着Monad
是一个比你给予赞誉的更通用的界面。
答案 3 :(得分:8)
假设有这样一个功能:
extract :: Monad m => m a -> a
现在你可以写一个像这样的“功能”:
appendLine :: String -> String
appendLine str = str ++ extract getLine
除非保证extract
函数永远不会终止,否则会违反参照透明度,因为appendLine "foo"
的结果将(a)取决于"foo"
以外的其他内容,(b)在不同背景下评估时评估不同的值。
或者用更简单的话说,如果有一个实际有用的extract
操作,Haskell将不是纯粹的功能。
答案 4 :(得分:6)
是否有带签名
:: (Monad m) => m a -> a
的内置函数?
如果Hoogle说没有......那么可能没有,假设您对“内置”的定义是“在基础库中”。
Hoogle告诉我们没有这样的功能。你能解释一下原因吗?
这很简单,因为Hoogle在基础库中找不到与该类型签名匹配的任何功能!
更严重的是,我想你要求的是monadic解释。问题是安全和意味着。 (另见my previous thoughts on magicMonadUnwrap :: Monad m => m a -> a
)
假设我告诉你我有一个类型为[Int]
的值。由于我们知道[]
是一个monad,这类似于告诉你我有一个类型为Monad m => m Int
的值。因此,我们假设您希望从Int
中获取[Int]
。好吧,你想要哪Int
?第一个?最后一个?如果我告诉你的价值实际上是一个空列表怎么办?在这种情况下,甚至没有Int
给你!因此对于列表来说,尝试提取单个值就像不安全一样。即使它是安全的(非空列表),您也需要特定于列表的功能(例如,head
)以通过希望f :: [Int] -> Int
来阐明您的含义。希望你能从这里知道Monad m => m a -> a
的含义根本没有明确定义。对于同一个monad来说它可能有多种含义,或者对于某些monad来说它可能意味着什么都没有,有时候,它只是不安全。
答案 5 :(得分:5)
因为它可能毫无意义(实际上, 在许多情况下没有意义)。
例如,我可能会像这样定义一个Parser Monad:
data Parser a = Parser (String ->[(a, String)])
现在绝对没有合理的默认方式来从String
中获取Parser String
。实际上,除了Monad之外,根本无法获得一个String。
答案 6 :(得分:1)
在http://hackage.haskell.org/package/comonad-5.0.4/docs/Control-Comonad.html有一个有用的extract
函数和一些与此相关的其他功能
它仅针对某些函子/单子定义,不一定提供完整的答案,而是给出一个答案。因此,可能会有comonad的子类,这些子类为您提供了可以控制答案的中间阶段。可能与Traversable的可能子类有关。我不知道是否在任何地方定义了这些东西。
为什么hoogle根本不列出此功能,这似乎是因为未对comonad程序包建立索引,否则我认为Monad约束将被警告,并且extract
将出现在带有{ {1}}个实例。也许是因为hoogle解析器不完整,并且在某些代码行上失败了。
我的替代答案:
Comonad
作为替代代码结构,将使用提取的值的代码链接到monad,只要您可以将monad转换为“ IO()”以打印输出你完成了。这看起来不像提取,但数学与现实世界并不相同。答案 7 :(得分:-1)
嗯,技术上IO monad有unsafePerformIO。
但是,正如名称本身所暗示的那样,这个功能是邪恶的,如果你真的知道你在做什么,你应该只使用它(如果你不知道你是否知道,那么你不)