[英]How to extract value from monadic action
Is there a built-in function with signature :: (Monad m) => ma -> a
? 是否存在带有签名
:: (Monad m) => ma -> a
的内置函数?
Hoogle tells that there is no such function. Hoogle告诉我们没有这样的功能。
Can you explain why? 你能解释为什么吗?
A monad only supplies two functions: 一个monad仅提供两个功能:
return :: Monad m => a -> m a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Both of these return something of type ma
, so there is no way to combine these in any way to get a function of type Monad m => ma -> a
. 两者都返回类型为
ma
东西,因此无法以任何方式将它们组合起来以获得类型Monad m => ma -> a
的函数Monad m => ma -> a
。 To do that, you'll need more than these two functions, so you need to know more about m
than that it's a monad. 为此,您需要的不仅仅是这两个函数,因此您需要了解更多有关
m
不是m
。
For example, the Identity
monad has runIdentity :: Identity a -> a
, and several monads have similar functions, but there is no way to provide it generically. 例如,
Identity
monad具有runIdentity :: Identity a -> a
,并且几个monad具有相似的功能,但是无法通用地提供它。 In fact, the inability to "escape" from the monad is essential for monads like IO
. 实际上,对于像
IO
这样的单子来说,无法从单子中“逃脱”是至关重要的。
There is probably a better answer than this, but one way to see why you cannot have a type (Monad m) => ma -> a
is to consider a null monad: 可能有比这更好的答案,但是查看为什么不能拥有类型
(Monad m) => ma -> a
是考虑空monad:
data Null a = Null
instance Monad Null where
return a = Null
ma >>= f = Null
Now (Monad m) => ma -> a
means Null a -> a
, ie getting something out of nothing. 现在
(Monad m) => ma -> a
表示Null a -> a
,即从空中得到一些东西。 You can't do that. 你不能那样做。
This doesn't exist because Monad
is a pattern for composition, not a pattern for decomposition. 这不存在,因为
Monad
是合成的模式,而不是分解的模式。 You can always put more pieces together with the interface it defines. 您始终可以将更多片段与其定义的界面放在一起。 It doesn't say a thing about taking anything apart.
它没有说要拆散任何东西。
Asking why you can't take something out is like asking why Java's Iterator
interface doesn't contain a method for adding elements to what it's iterating over. 问为什么不能取出某些东西就像问为什么Java的
Iterator
接口不包含用于在其迭代的内容中添加元素的方法。 It's just not what the Iterator
interface is for. 这不是
Iterator
接口的用途。
And your arguments about specific types having a kind of extract function follows in the exact same way. 关于具有提取函数类型的特定类型的论点也完全相同。 Some particular implementation of
Iterator
might have an add
function. Iterator
某些特定实现可能具有add
功能。 But since it's not what Iterator
s are for, the presence that method on some particular instance is irrelevant. 但是由于不是
Iterator
的目的,因此该方法在某些特定实例上的存在无关紧要。
And the presence of fromJust
is just as irrelevant. 与
fromJust
的存在无关紧要。 It's not part of the behavior Monad
is intended to describe. 这不是
Monad
打算描述的行为的一部分。 Others have given lots of examples of types where there is no value for extract
to work on. 其他人给出了很多类型的示例,这些示例没有任何可
extract
价值。 But those types still support the intended semantics of Monad
. 但是这些类型仍然支持
Monad
的预期语义。 This is important. 这个很重要。 It means that
Monad
is a more general interface than you are giving it credit for. 这意味着
Monad
是比您所称赞的更通用的界面。
Suppose there was such a function: 假设有这样一个功能:
extract :: Monad m => m a -> a
Now you could write a "function" like this: 现在您可以编写这样的“函数”:
appendLine :: String -> String
appendLine str = str ++ extract getLine
Unless the extract
function was guaranteed never to terminate, this would violate referential transparency, because the result of appendLine "foo"
would (a) depend on something other than "foo"
, (b) evaluate to different values when evaluated in different contexts. 除非保证
extract
函数永远不会终止,否则这将违反参照透明性,因为appendLine "foo"
的结果将(a)依赖于"foo"
以外的东西,(b)在不同上下文中求值时会得出不同的值。
Or in simpler words, if there was an actually useful extract
operation Haskell would not be purely functional. 或者用简单的话来说,如果有一个实际上有用的
extract
操作,Haskell将不能纯粹地发挥作用。
Is there a build-in function with signature
:: (Monad m) => ma -> a
?是否存在带有签名
:: (Monad m) => ma -> a
的内置函数?
If Hoogle says there isn't...then there probably isn't, assuming your definition of "built in" is "in the base libraries". 如果Hoogle说没有……那么可能就没有了,假设您对“内置”的定义是“在基础库中”。
Hoogle tells that there is no such function.
Hoogle告诉我们没有这样的功能。 Can you explain why?
你能解释为什么吗?
That's easy, because Hoogle didn't find any function in the base libraries that matches that type signature! 这很容易,因为Hoogle在基库中找不到与该类型签名匹配的任何函数!
More seriously, I suppose you were asking for the monadic explanation. 更严重的是,我想您是在要求单子说明。 The issues are safety and meaning .
问题是安全和意义 。 (See also my previous thoughts on
magicMonadUnwrap :: Monad m => ma -> a
) (另请参阅我以前对
magicMonadUnwrap :: Monad m => ma -> a
想法magicMonadUnwrap :: Monad m => ma -> a
)
Suppose I tell you I have a value which has the type [Int]
. 假设我告诉你我有一个
[Int]
类型的值。 Since we know that []
is a monad, this is similar to telling you I have a value which has the type Monad m => m Int
. 既然我们知道
[]
是一个monad,这类似于告诉您我有一个类型为Monad m => m Int
。 So let's suppose you want to get the Int
out of that [Int]
. 因此,假设您
Int
[Int]
获取[Int]
。 Well, which Int
do you want? 好吧,您想要哪个
Int
? The first one? 第一个? The last one?
最后一个? What if the value I told you about is actually an empty list?
如果我告诉您的值实际上是一个空列表怎么办? In that case, there isn't even an
Int
to give you! 在这种情况下,甚至没有一个
Int
可以给您! So for lists, it is unsafe to try and extract a single value willy-nilly like that. 因此,对于列表,尝试像这样随意地提取单个值是不安全的 。 Even when it is safe (a non-empty list), you need a list-specific function (for example,
head
) to clarify what you mean by desiring f :: [Int] -> Int
. 即使是安全的(非空列表),也需要特定于列表的函数(例如
head
)来通过f :: [Int] -> Int
来阐明您的意思 。 Hopefully you can intuit from here that the meaning of Monad m => ma -> a
is simply not well defined. 希望您可以从这里了解到
Monad m => ma -> a
的含义并没有被很好地定义。 It could hold multiple meanings for the same monad, or it could mean absolutely nothing at all for some monads, and sometimes, it's just simply not safe. 它对于同一个monad可能具有多种含义,或者对于某些monad绝对没有任何意义,有时,这只是不安全的。
Because it may make no sense (actually, does make no sense in many instances). 因为它可能没有任何意义(实际上,在许多情况下确实没有任何意义)。
For example, I might define a Parser Monad like this: 例如,我可以这样定义一个解析器Monad:
data Parser a = Parser (String ->[(a, String)])
Now there is absolutely no sensible default way to get a String
out of a Parser String
. 现在是绝对没有合理的默认方式来获得一个
String
出的Parser String
。 Actually, there is no way at all to get a String out of this with just the Monad. 实际上,仅凭Monad根本无法从中获得String。
There is a useful extract
function and some other functions related to this at http://hackage.haskell.org/package/comonad-5.0.4/docs/Control-Comonad.html 在http://hackage.haskell.org/package/comonad-5.0.4/docs/Control-Comonad.html上有一个有用的
extract
功能以及与此相关的其他一些功能。
It's only defined for some functors/monads and it doesn't necessarily give you the whole answer but rather gives an answer. 这只是对一些仿函数/单子定义,它并不一定给你全部答案,而是给出了一个答案。 Thus there will be possible subclasses of comonad that give you intermediate stages of picking the answer where you could control it.
因此,可能会有comonad的子类,这些子类为您提供了可以控制答案的中间阶段。 Probably related to the possible subclasses of Traversable.
可能与Traversable的可能子类有关。 I don't know if such things are defined anywhere.
我不知道是否在任何地方定义了这些东西。
Why hoogle doesn't list this function at all appears to be because the comonad package isn't indexed otherwise I think the Monad constraint would be warned and extract
would be in the results for those Monads with a Comonad
instance. 为什么hoogle根本不列出此功能,似乎是因为未对comonad程序包建立索引,否则我认为将警告Monad约束,并将
extract
出具有Comonad
实例的Monad的结果。 Perhaps this is because the hoogle parser is incomplete and fails on some lines of code. 也许是因为hoogle解析器不完整,并且在某些代码行上失败了。
My alternative answers: 我的替代答案:
monad >>= \\a -> return $ your code uses a here
as an alternative code structure and as long as you can convert the monad to "IO ()" in a way that prints your outputs you're done. monad >>= \\a -> return $ your code uses a here
将使用提取的值的代码链接到monad中,只要您可以将monad转换为“ IO()”, monad >>= \\a -> return $ your code uses a here
作为替代代码结构。以打印输出的方式完成。 This doesn't look like extraction but maths isn't the same as the real world. Well, technicaly there is unsafePerformIO for the IO monad. 好吧,从技术上讲 ,IO monad有unsafePerformIO 。
But, as the name itself suggests, this function is evil and you should only use it if you really know what you are doing (and if you have to ask wether you know or not then you don't) 但是,顾名思义,此功能是有害的,只有在真正知道自己在做什么的情况下才应使用它(并且如果必须询问是否知道,那么就不知道)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.