【问题标题】:Is there bindN in default libraries?默认库中有 bindN 吗?
【发布时间】:2014-11-05 09:24:25
【问题描述】:

我想知道标准包中是否定义了bind2、bind3等函数?

bind2 :: (Monad m, Applicative m) => (a -> b -> m c) -> m a -> m b -> m c
bind2 f a b = join (liftA2 a b)

为什么我想要那个?因为我想将绑定减少到最低限度。例如,如果我们使用免费的 monad 方法来构建自动并发异步计算,或者像 Haxl 中那样获取:

fetchForSuggestions :: Artist -> [Like] -> Async [Suggestions]
fetchForSuggestions = error "implement me"

-- Two binds!
action :: ArtistId -> UserId -> Async [Suggestions]
action artistId userId = do
  artist <- fetchArtist artistId
  likes <- fetchUserLikes userId
  fetchForSuggestions artist likes

-- Single bind
-- here artist and user likes could be fetched concurrently
action :: ArtistId -> UserId -> Async [Suggestions]
action artistId userId = bind2 fetchForSuggestions (fetchArtist artistId) (fetchUserLikes userId)

我在这里介绍某种反模式吗?我应该尝试做什么:

complexAction :: ParamA -> ParamB -> ParamC -> Async Result
complexAction a b c = do
  (x, y, z) <- (,,) <$> subActionX a b <*> subActionY b c <*> subActionZ c a
  (i, j, k) <- (,,) <$> subActionI a x <*> subActionJ b y <*> subActionK c z
  finalAction i j k x y z

每个subAction 函数在哪里是无绑定的? IE。去掉action,取ArtistIdUserId,只留下fetchForSuggestions

【问题讨论】:

标签: haskell monads applicative


【解决方案1】:

使用AMP,您应该可以只写f &lt;$&gt; a &lt;*&gt; b,其中f :: (Applicative m) =&gt; a -&gt; b -&gt; ca :: (Applicative m) =&gt; m ab :: (Applicative m) m b。由于 AMP 在 GHC Head 中通过(截至 2014 年 9 月),您现在实际上可以这样做了!你的代码变成:

action artistId userId =
  join (fetchForSuggestions <$> fetchArtist artistId <*> fetchUserLikes userId)

这现在适用于 GHC Head 中的任何 Monad,我认为它也适用于 7.8.3,并且肯定会在 7.10 中有效。

巧妙的是,这是通用的。对于任何 n 元动作k :: a_1 -&gt; ... -&gt; a_n -&gt; m c,你可以写

join (k <$> (x_1 :: a_1) <*> ... <*> (x_n :: a_n)) :: m c

不过,一般来说,这种表示法并不比仅使用多个 do 绑定好得多。我认为您必须仔细考虑哪一个更具可读性。使用多个绑定不是一种反模式,而且实际上经常发生。 bind2do 语法几乎不需要,我认为它不存在。

【讨论】:

  • f &lt;$&gt; x &lt;*&gt; y 中,f 通常是a -&gt; b -&gt; c 类型。你错过了我需要的join
  • 你当然是对的。这就是我在工作中快速汇总答案所得到的:-P
  • do { a &lt;- ma; b &lt;- mb; f a b } 在脱糖时有两个 &gt;&gt;=。对我来说,尽可能少地绑定很重要。我会把它改写成do { (a, b) &lt;- (,) &lt;$&gt; ma &lt;*&gt; mb; f a b }join (f &lt;$&gt; ma &lt;*&gt; mb),就像你提出的那样,但是bind2 f ma mb 恕我直言更具可读性。 ApplicativeDo 会解决这个问题,但还没有。
  • 为什么尽可能少的绑定如此重要?如果您关心性能,那么所有替代方案(包括join + fmap + &lt;*&gt;,以及您的bind2,因为liftA2 完全相同)不是不会好很多。 (尽管您不应该相信我的话,而是用标准来衡量它。)如果“代码优雅”是您的目标,我不认为多重绑定是不受欢迎的,或者以任何方式在风格上不好。
  • 检查code.facebook.com/posts/302060973291128/… 的原因是我希望尽可能少地绑定。
猜你喜欢
  • 1970-01-01
  • 2011-01-18
  • 2018-06-20
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多