如何从monadic行动中提取价值
是否有一个内置函数签名:: (Monad m) => ma -> a
?
霍格尔说,没有这样的function。
你能解释一下为什么?
monad只提供两个function:
return :: Monad m => a -> ma (>>=) :: Monad m => ma -> (a -> mb) -> mb
这两个都返回ma
types的东西,所以没有办法把这些以任何方式组合起来得到Monad m => ma -> a
types的函数。 要做到这一点,你需要的不仅仅是这两个函数,所以你需要知道更多关于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 Int
types的值。 所以我们假设你想从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是邪恶的,如果你真的知道自己在做什么,那么你只能使用它(如果你必须问问你是否知道,那么你就不知道)