如何从monadic行动中提取价值

是否有一个内置函数签名:: (Monad m) => ma -> a

霍格尔说,没有这样的function。

你能解释一下为什么?

monad只提供两个function:

 return :: Monad m => a -> ma (>>=) :: Monad m => ma -> (a -> mb) -> mb 

这两个都返回matypes的东西,所以没有办法把这些以任何方式组合起来得到Monad m => ma -> atypes的函数。 要做到这一点,你需要的不仅仅是这两个函数,所以你需要知道更多关于m不是monad。

例如, Identity monad具有runIdentity :: Identity a -> a ,并且几个monad具有相似的function,但是没有办法一般地提供它。 事实上,无法从monad中“逃脱”,对于像IO这样的monad来说是至关重要的。

可能有比这更好的答案,但要明白为什么你不能有一个types(Monad m) => ma -> a是考虑一个null monad:

 data Null a = Null instance Monad Null where return a = Null ma >>= f = Null 

现在(Monad m) => ma -> a表示Null a -> a ,即从无到有。 你不能这样做。

这是不存在的,因为Monad是组合模式,而不是分解模式。 你总是可以把更多的作品与它定义的界面放在一起。 它没有说任何东西分开。

问为什么你不能拿出一些东西,就像是问为什么Java的Iterator接口不包含一个方法来添加元素到迭代中。 这不仅仅是Iterator接口的用途。

而关于具有一种提取function的具体types的论点也完全一样。 Iterator一些特定的实现可能有一个add函数。 但是由于这不是Iterator的作用,所以在某些特定实例上的这种方法是不相关的。

fromJust的存在也是无关紧要的。 这不是Monad打算描述的行为的一部分。 其他人已经提供了很多types的例子,其中没有extract价值。 但是这些types仍然支持Monad的预期语义。 这个很重要。 这意味着Monad是一个更为一般的界面,而不是您所称赞的。

假设有这样一个function:

 extract :: Monad m => ma -> a 

现在你可以写一个这样的“函数”:

 appendLine :: String -> String appendLine str = str ++ extract getLine 

除非extract函数被保证永不终止,否则这将违反参考透明性,因为appendLine "foo"的结果将(a)取决于除"foo"以外的其他内容,(b)在不同的上下文中评估不同的值。

或者用更简单的话来说,如果实际上有用的extract操作,Haskell将不会是纯粹的function。

有签名:: (Monad m) => ma -> a的内置函数吗?

如果Hoogle说没有…那么可能不存在,假设你的“内置”定义是“在基础库”中。

霍格尔说,没有这样的function。 你能解释一下为什么?

这很容易,因为Hoogle在基本库中没有find与该types签名相匹配的任何函数!

更严重的是,我想你是在寻求单调的解释。 这些问题是安全意义的 。 (另请参阅我之前对magicMonadUnwrap :: Monad m => ma -> a看法 )

假设我告诉你我有一个types为[Int] 。 既然我们知道[]是一个monad,这就类似于告诉你我有一个Monad m => m Inttypes的值。 所以我们假设你想从Int [Int]得到[Int] 。 那么,你想要哪个Int ? 第一个? 最后一个? 如果我告诉你的价值实际上是一个空的列表呢? 在这种情况下,甚至没有一个Int给你! 因此,对于列表来说,尝试提取一个单一的值是不安全的 。 即使是安全的(一个非空的列表),你也需要一个特定于列表的函数(例如head )来阐明你所期望的f :: [Int] -> Int 。 希望你可以从这里直觉, Monad m => ma -> a含义根本就没有明确定义。 它可能对同一个monad具有多重意义,或者对于一些monad可能意味着什么都没有,有时候,这根本就不安全。

因为它可能没有意义(实际上,在许多情况下是没有意义的)。

例如,我可能会像这样定义一个Parser Monad:

 data Parser a = Parser (String ->[(a, String)]) 

现在绝对没有合理的默认方式来从一个Parser String获取一个Parser String 。 实际上,只用Monad就没有办法获得一个String。

那么,技术上有IO monad的unsafePerformIO 。

但是,正如名字所暗示的那样,这个function是邪恶的,如果你真的知道自己在做什么,那么你只能使用它(如果你必须问问你是否知道,那么你就不知道)