首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于两个不同函子的应用类型化

基于两个不同函子的应用类型化
EN

Stack Overflow用户
提问于 2019-04-17 12:35:06
回答 3查看 167关注 0票数 3

是否有类似于Applicative类型类的东西,但是应用程序的每端有两个不同的函子呢?

(<*>) :: (Functor f, Functor g) => f (a -> b) -> g a -> f b

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-04-17 19:14:58

(在评论中遵循@dfeuer的建议。)

有一个名为日卷积的构造,它允许您在执行应用程序操作时保留两个函子之间的区别,并延迟将其中一个转换为另一个函子的时刻。

Day类型只是一对函数值,以及一个结合各自结果的函数:

代码语言:javascript
复制
data Day f g a = forall b c. Day (f b) (g c) (b -> c -> a)

注意,函子的实际返回值是存在的;组合的返回值是函数的返回值。

Day在组合应用函子方面具有其他方法的优势。与Sum不同的是,该组合仍然是可应用的。与Compose不同的是,这种组合是“无偏见的”,不会强制执行嵌套顺序。与Product不同,它允许我们轻松地将不同返回类型的应用程序操作组合起来,我们只需要提供一个合适的适配器功能。

例如,下面是两个Day ZipList (Vec Nat2) Char值:

代码语言:javascript
复制
{-# LANGUAGE DataKinds #-}
import           Data.Functor.Day -- from "kan-extensions"
import           Data.Type.Nat -- from "fin"
import           Data.Vec.Lazy -- from "vec"
import           Control.Applicative

day1 :: Day ZipList (Vec Nat2) Char
day1 = Day (pure ()) ('b' ::: 'a' ::: VNil) (flip const)

day2 :: Day ZipList (Vec Nat2) Char
day2 = Day (ZipList "foo") (pure ()) const

(Nat2来自鱼鳍包,用于从vec参数化固定大小的Vec。)

我们可以把它们拉在一起很好:

代码语言:javascript
复制
res :: Day ZipList (Vec Nat2) (Char,Char)
res = (,) <$> day1 <*> day2

然后将Vec转换为ZipList并折叠Day

代码语言:javascript
复制
res' :: ZipList (Char,Char)
res' = dap $ trans2 (ZipList . toList) res

ghci> res'
ZipList {getZipList = [('b','f'),('a','o')]}

使用daptrans2函数。

可能的性能陷阱:当我们将其中一个函子提升到Day时,给另一个函子一个虚拟的pure ()值。但是当将Day(<*>)结合起来时,这是自重的。我们可以通过将函子包装在Lift中用于变压器,从而更聪明地工作,以便在简单的“纯”情况下获得更快的操作。

票数 5
EN

Stack Overflow用户

发布于 2019-04-17 18:24:02

“序列类型”的一个一般概念是自由幺半群。因为您正在研究多态序列类型,所以我们可以在Traversable上进行构建。

代码语言:javascript
复制
class Semigroup1 t where
  (<=>) :: t a -> t a -> t a

class Semigroup1 t => Monoid1 t where
  mempty1 :: t a

见下文注。

代码语言:javascript
复制
class (Traversable t, Monoid1 t) => Sequence t where
  singleton :: a -> t a

那怎么是序列类型?效率很低。但是,我们可以添加一组具有默认实现的方法,以提高效率。以下是一些基本功能:

代码语言:javascript
复制
cons :: Sequence t => a -> t a -> t a
cons x xs = singleton x <=> xs

fromList
  :: (Foldable f, Sequence t)
  => f a -> t a
fromList = foldr cons mempty1

uncons :: Sequence t => t a -> Maybe (a, t a)
uncons xs = case toList xs of
  y:ys -> Just (y, fromList ys)
  [] -> Nothing

使用这些工具,您可以将任意两个序列压缩为第三个序列。

代码语言:javascript
复制
zipApp :: (Foldable t, Foldable u, Sequence v) = t (a -> b) -> u a -> v b
zipApp fs xs = fromList $ zipWith ($) (toList fs) (toList xs)

关于GHC最新版本的说明

对于出血边缘GHC,可以使用QuantifiedConstraintsRankNTypesConstraintKinds并定义

代码语言:javascript
复制
type Semigroup1 t = forall a. Semigroup (t a)

type Monoid1 t = forall a. Monoid (t a)

这样做会让你写作,例如,

代码语言:javascript
复制
fromList = foldMap singleton
票数 2
EN

Stack Overflow用户

发布于 2019-04-17 14:08:35

从你的评论中,我认为你可能试图构建:

代码语言:javascript
复制
import Data.Foldable
import Data.Traversable
foo :: (Traversable f, Foldable g) => f (a -> b) -> g a -> f b
foo f g = snd $ mapAccumR (\(a:as) fab -> (as, fab a)) (toList g) f

例如,这允许:

代码语言:javascript
复制
> import qualified Data.Vector as V
> foo [(+1),(+2),(+3)] (V.fromList [5,6,7])
[8,8,8]
> 
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55727699

复制
相关文章

相似问题

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