Haskell 如何从一元行为中提取价值
是否有带有签名的内置函数Haskell 如何从一元行为中提取价值,haskell,monads,comonad,Haskell,Monads,Comonad,是否有带有签名的内置函数:(Monad m)=>ma->a Hoogle说没有这样的功能 你能解释一下原因吗?因为它可能没有意义(实际上,在许多情况下没有意义) 例如,我可以这样定义解析器Monad: data Parser a = Parser (String ->[(a, String)]) appendLine :: String -> String appendLine str = str ++ extract getLine 现在,从解析器字符串中获取字符串绝对没有合理
:(Monad m)=>ma->a
Hoogle说没有这样的功能
你能解释一下原因吗?因为它可能没有意义(实际上,在许多情况下没有意义) 例如,我可以这样定义解析器Monad:
data Parser a = Parser (String ->[(a, String)])
appendLine :: String -> String
appendLine str = str ++ extract getLine
现在,从
解析器字符串
中获取字符串
绝对没有合理的默认方法。实际上,根本没有办法用单元格得到一个字符串。 也许有比这更好的答案,但是有一种方法可以看出为什么你不能有一个类型<代码>(Monad m)=m a->a < /> >考虑一个空单元格:
data Null a = Null
instance Monad Null where
return a = Null
ma >>= f = Null
现在
(Monad m)=>ma->a
意味着空a->a
,即从无到有。你不能那样做。单子只提供两个功能:
return :: Monad m => a -> m a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
这两个函数都返回ma
类型的函数,因此无法以任何方式组合它们以获得Monad m=>ma->a
类型的函数。要做到这一点,您需要的不仅仅是这两个函数,因此您需要更多地了解m
,而不是它是一个monad
例如,
Identity
monad具有runIdentity::Identity a->a
,并且有几个monad具有类似的功能,但无法提供通用的功能。事实上,无法从单子中“逃逸”对于像IO
这样的单子是至关重要的,因为monad
是一种合成模式,而不是分解模式。您总是可以将更多的片段与它定义的接口放在一起。它没有说要拆开任何东西
询问为什么不能取出某些内容就像询问为什么Java的Iterator
接口不包含向其迭代的内容添加元素的方法一样。这不是迭代器接口的功能
你关于特定类型有一种提取函数的论点也是这样的。Iterator
的某些特定实现可能具有add
函数。但是,由于它不是迭代器的作用,因此在某些特定实例上该方法的存在是不相关的
而fromJust的的存在也同样无关紧要。它不是Monad所要描述的行为的一部分。其他人给出了许多类型的示例,其中没有extract
可以使用的值。但是这些类型仍然支持Monad
的预期语义。这很重要。这意味着Monad
是一个比您认为的更通用的接口
是否有签名为:(Monad m)=>ma->a的内置函数
如果Hoogle说没有……那么可能没有,假设您对“内置”的定义是“在基本库中”
Hoogle说没有这样的功能。你能解释一下原因吗
这很简单,因为Hoogle在基本库中没有找到任何与该类型签名匹配的函数
更严重的是,我想你是在要求一元解释。问题是安全和意义。(另见)
假设我告诉你我有一个类型为[Int]
的值。因为我们知道[]
是一个monad,这类似于告诉您我有一个类型为monad m=>m Int
的值。因此,假设您想从[Int]
中获取Int
。那么,你想要哪个Int
?第一个?最后一个?如果我告诉你的值实际上是一个空列表呢?在这种情况下,甚至没有一个Int
给你!所以对于列表来说,像这样任意抽取一个值是不安全的。即使是在安全的情况下(非空列表),您也需要一个特定于列表的函数(例如,head
)来阐明希望f::[Int]>Int
的含义。希望您能从这里直觉地看出,Monad m=>ma->a
的含义并没有很好地定义。它可能对同一个单子有多种含义,也可能对某些单子毫无意义,有时,它只是不安全。假设有这样一个函数:
extract :: Monad m => m a -> a
现在您可以编写如下“函数”:
data Parser a = Parser (String ->[(a, String)])
appendLine :: String -> String
appendLine str = str ++ extract getLine
除非extract
函数被保证永不终止,否则这将违反引用透明度,因为附录行“foo”
的结果将(a)依赖于“foo”
以外的内容,(b)在不同上下文中求值时,求值结果将不同
或者更简单地说,如果有一个真正有用的提取操作,Haskell就不会是纯粹的功能性操作了。好吧,从技术上讲,IO单子是有的
但是,正如名字本身所暗示的,这个函数是邪恶的,只有当你真正知道自己在做什么时才应该使用它(如果你必须问自己知道与否,那么你就不知道)这里有一个有用的提取
函数和一些其他与此相关的函数
它只为一些函子/单子定义,它不一定给出完整的答案,而是给出一个答案。因此,可能会有comonad的子类,它们为您提供了选择答案的中间阶段,您可以在其中控制答案。可能与Traversable的可能子类有关。我不知道这些东西是否在任何地方都有定义
hoogle根本没有列出这个函数的原因似乎是因为comonad包没有索引,否则我认为Monad约束会被警告,extract
会出现在带有comonad
实例的Monad的结果中。这可能是因为hoogle解析器不完整,并且在某些代码行中失败
我的备选答案是:
您可以执行一个-可能重复