首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Data.Traversable中的“for”接受一元操作?

为什么Data.Traversable中的“for”接受一元操作?
EN

Stack Overflow用户
提问于 2016-12-14 19:06:52
回答 2查看 132关注 0票数 3

我正在编写以下代码片段:

代码语言:javascript
复制
import           Control.Monad
import           Data.Aeson
import qualified Data.HashMap.Strict as HashMap
import           Data.Map (Map)
import qualified Data.Map as Map
import           GHC.Generics

-- definitions of Whitelisted, WhitelistComment and their FromJSON instances
-- omitted for brevity

data Whitelist = Whitelist
  { whitelist :: Map Whitelisted WhitelistComment
  } deriving (Eq, Ord, Show)

instance FromJSON Whitelist where
  parseJSON (Object v) =
    fmap (Whitelist . Map.fromList) . forM (HashMap.toList v) $ \(a, b) -> do
      a' <- parseJSON (String a)
      b' <- parseJSON b
      return (a', b')
  parseJSON _ = mzero

当我意识到我可以用应用程序的方式重写do块时:

代码语言:javascript
复制
instance FromJSON Whitelist where
  parseJSON (Object v) =
    fmap (Whitelist . Map.fromList) . forM (HashMap.toList v) $ \(a, b) ->
      (,) <$> parseJSON (String a) <*> parseJSON b
  parseJSON _ = mzero

这样,我也可以用for代替for。在进行上述更改之前,我首先切换到了for

代码语言:javascript
复制
instance FromJSON Whitelist where
  parseJSON (Object v) =
    fmap (Whitelist . Map.fromList) . for (HashMap.toList v) $ \(a, b) -> do
      a' <- parseJSON (String a)
      b' <- parseJSON b
      return (a', b')
  parseJSON _ = mzero

令我惊讶的是,这仍然是汇编的。给出for定义

代码语言:javascript
复制
for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)

我认为Applicative约束会阻止我在传递给for的操作中使用do表示法/返回。

在这里,我显然缺少了一些基本的东西,无论是关于for签名真正意味着什么,还是我发布的代码是如何被编译器解释的,并且希望能帮助理解所发生的事情。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-14 19:30:32

第一个简短的答案是Parser有一个Applicative实例。小片段

代码语言:javascript
复制
do
  a' <- parseJSON a
  b' <- parseJSON b
  return (a', b')

具有类型Parser (Whitelisted, WhitelistComment),它在类型签名中与f b统一。

代码语言:javascript
复制
for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)

因为有一个Applicative Parser实例,所以它也满足了这个约束。(我认为a'b'的类型是正确的)

第二个简短的答案是,MonadApplicative更强大,只要您需要Applicative,就可以使用Monad。自从提案实现以来,每个Monad都是ApplicativeMonad类现在看起来像

代码语言:javascript
复制
class Applicative m => Monad m where 
    ...

MonadApplicative功能更强大,在任何需要Applicative的地方,您都可以使用Monad替换如下:

  • 接入点而不是<*>
  • return而不是pure
  • liftM而不是fmap

如果您正在编写某种新类型SomeMonad,并且为Monad类提供了一个实例,您也可以使用它为ApplicativeFunctor提供实例。

代码语言:javascript
复制
import Control.Monad

instance Applicative SomeMonad where
    pure = return
    (<*>) = ap

instance Functor SomeMonad where
    fmap = liftM
票数 5
EN

Stack Overflow用户

发布于 2016-12-14 23:23:35

这只是通常的调用者-vs-实现者二元性,其中一方获得灵活性,而另一方则受到限制。

for为您提供了以下接口:

代码语言:javascript
复制
for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)

作为调用方,您可以灵活地选择任何类型的f来实例化它,这样您就可以像使用它一样使用它:

代码语言:javascript
复制
for :: Traversable t => t a -> (a -> Parser b) -> Parser (t b)

显然,一旦您这样做了,您就没有理由不能在传递给Parser的函数中使用任何-specific功能,包括Monad之类的功能。

另一方面,for的实现者受到for接口多态性的限制。他们必须使用--任何选择的f,所以他们只能在为实现for而编写的代码中使用Applicative接口。但这只会限制for本身的代码,而不是传递给它的函数。

如果for的作者想限制调用者在该函数中可以做什么,他们可以使用RankNTypes来提供这个接口:

代码语言:javascript
复制
for :: forall t f. (Traversable t, Applicative f) => t a -> (forall g. Applicative g => a -> g b) -> f (t b)

现在,提供的lambda本身在g中必须是多态的(受Applicative约束)。for的调用方仍然可以灵活地选择f,实现者仅限于使用Applicative特性。但是,for的调用者是函数参数的实现者,因此,既然该函数本身是多态的,那么for的调用者只能在那里使用Applicative特性,而for的实现者可以自由地将它与他们喜欢的任何类型一起使用(包括可能使用monad特性将其与其他内部值组合起来)。有了这个特定类型的签名,for的实现者将不得不选择用为f选择的for调用者的相同类型实例化g,以便得到最终的f (t b)返回值。但是for的调用者仍然受到类型系统的限制,只能提供一个适用于任何Applicative g的函数。

关键是,如果您选择使用哪种类型实例化多态签名,那么您就不会受到该接口的限制。您可以选择一个类型,然后使用该类型的任何其他功能,只要您仍然提供接口所需的信息。也就是说,您可以使用非Traversable功能来创建您的t a,使用非Applicative功能来创建您的a -> f b,所需要的只是提供这些输入。实际上,您几乎必须使用特定于ab的功能。多态签名的实现者并没有得到这种自由,他们受到多态性的限制,只做那些为任何可能的选择工作的事情。

顺便说一句,类似于等级2类型如何在角色反转的情况下添加这种二元性的“另一个层次”(而秩N类型允许任意多个级别),在约束本身中也可以看到类似的二元性(再次翻转)。再考虑一下签名:

代码语言:javascript
复制
for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)

for的调用方在选择tf类型时受到TraversableApplicative约束的限制。实现者可以自由地使用这些约束所隐含的任何函数,而不必担心如何证明这些约束是满足的。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41150270

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档