加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 折叠flatMap /绑定在函数列表(a.k.a. Name Combinator

发布时间:2020-12-16 09:11:08 所属栏目:安全 来源:网络整理
导读:在编写简单的RPN计算器的过程中,我有以下类型的别名: type Stack = List[Double]type Operation = Stack = Option[Stack] …我写了一个好奇的Scala代码: val newStack = operations.foldLeft(Option(stack)) { _ flatMap _ } 这需要一个初始的值堆栈,并将
在编写简单的RPN计算器的过程中,我有以下类型的别名:

type Stack = List[Double]
type Operation = Stack => Option[Stack]

…我写了一个好奇的Scala代码:

val newStack = operations.foldLeft(Option(stack)) { _ flatMap _ }

这需要一个初始的值堆栈,并将一个操作列表应用于堆栈.每个操作可能会失败(即产生一个Option [Stack]),所以我用flatMap进行排序.这个有点不寻常的事情(在我看来)是我折叠在一个单一的功能列表上,而不是折叠数据列表.

我想知道是否有一个标准函数捕获这种“折叠绑定”行为.当我试图玩“组合名称”游戏时,Hoogle通常是我的朋友,所以我在Haskell中尝试了同样的精神锻炼:

foldl (>>=) (Just stack) operations

这里的类型是:

foldl :: (a -> b -> a) -> a -> [b] -> a
(>>=) :: Monad m => m a -> (a -> m b) -> m b

所以我的神秘折叠(>> =)组合器的类型在将折叠类型和(>> =)排成一行之后应该是:

mysteryCombinator :: Monad m => m a -> [a -> m a] -> m a

…这又是我们所期望的.我的问题是,使用该类型的功能搜索Hoogle不会产生任何结果.我尝试了一些其他排列,我认为可能是合理的:a – > [a – > m a] – > m a(即以非单值开始),[a – > m a] – > m a – > m(即参数翻转),但也没有运气.所以我的问题是,有没有人知道我的神秘“折叠绑定”组合器的标准名称?

解决方法

a – > m a只是一个Kleisli箭头,参数和结果类型都是一个. Control.Monad.(>=>)组成两个Kleisli箭:

(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c

想想翻转(.),但是Kleisli箭头而不是功能.

所以我们可以把这个组合器分为两部分,组合和“应用”:

composeParts :: (Monad m) => [a -> m a] -> a -> m a
composeParts = foldr (>=>) return

mysteryCombinator :: (Monad m) => m a -> [a -> m a] -> m a
mysteryCombinator m fs = m >>= composeParts fs

现在,(> =>)和flip(.)在更深的意义上与仅仅是类似相关;函数箭头( – >)和包装Kleisli箭头Kleisli的数据类型都是Control.Category.Category的实例.所以如果我们要导入该模块,我们实际上可以将composeParts重写为:

composeParts :: (Category cat) => [cat a a] -> cat a a
composeParts = foldr (>>>) id

(>>>)(在Control.Category中定义)只是一种更好的写作方式作为翻转(.).

所以,我没有标准的名字,但它只是组成一个功能列表的一般化.标准库中有一个Endo类型,包含 – > a并有一个Monoid的实例,其中mempty是id,mappend是(.);我们可以将其推广到任何类别:

newtype Endo cat a = Endo { appEndo :: cat a a }

instance (Category cat) => Monoid (Endo cat a) where
  mempty = Endo id
  mappend (Endo f) (Endo g) = Endo (f . g)

然后我们可以将composeParts实现为:

composeParts = appEndo . mconcat . map Endo . reverse

这只是mconcat.与一些包装反向.然而,我们可以避免相反的情况,因为实例使用(.)而不是(>>>),通过使用双重Monoid,它只是将一个monoid转换成一个与翻转的mappend:

composeParts :: (Category cat) => [cat a a] -> cat a a
composeParts = appEndo . getDual . mconcat . map (Dual . Endo)

这表明composeParts在某种意义上是一个“明确定义的模式”:)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读