是否有类似于Applicative
类型的类,但是应用程序的每一侧有两个仿函数是不同的?
即yaazkssvpoi
(根据评论中@dfeuer的建议。)
有一个名为(<*>) :: (Functor f, Functor g) => f (a -> b) -> g a -> f b
的结构,可以让你在执行应用程序操作时保留两个仿函数之间的区别,并延迟将一个仿函数转换为另一个仿函数的时刻。
day convolution类型只是一对函数值,以及结合各自结果的函数:
Day
请注意,仿函数的实际返回值是存在的;组合的返回值是函数的返回值。
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
({-# 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
包,它用于参数化来自fin的固定大小的Vec
。)
我们可以把它们拉在一起就好了:
vec
然后将res :: Day ZipList (Vec Nat2) (Char,Char)
res = (,) <$> day1 <*> day2
变成Vec
并坍塌ZipList
:
Day
使用res' :: ZipList (Char,Char)
res' = dap $ trans2 (ZipList . toList) res
ghci> res'
ZipList {getZipList = [('b','f'),('a','o')]}
和dap
函数。
可能的性能问题:当我们将一个仿函数提升到trans2
时,另一个被赋予一个虚拟的Day
值。但是当将pure ()
s与Day
结合时,这是一个沉重的负担。通过在(<*>)
中包装变形金刚的仿函数,可以更聪明地工作,以便为简单的“纯”情况获得更快的操作。
“序列类型”的一个一般概念是自由的幺半群。既然你正在研究多态序列类型,我们可以建立在Lift
上。
Traversable
见下面的注释。
class Semigroup1 t where
(<=>) :: t a -> t a -> t a
class Semigroup1 t => Monoid1 t where
mempty1 :: t a
这是一个序列类型?非常低效。但是我们可以添加一些带有默认实现的方法来提高效率。以下是一些基本功能:
class (Traversable t, Monoid1 t) => Sequence t where
singleton :: a -> t a
使用这些工具,您可以将任意两个序列压缩成第三个。
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
对于前沿的GHC,你可以使用zipApp :: (Foldable t, Foldable u, Sequence v) = t (a -> b) -> u a -> v b
zipApp fs xs = fromList $ zipWith ($) (toList fs) (toList xs)
和QuantifiedConstraints
和RankNTypes
并定义
ConstraintKinds
这样做会让你写,例如,
type Semigroup1 t = forall a. Semigroup (t a)
type Monoid1 t = forall a. Monoid (t a)
从您的评论中,我认为您可能正在尝试构建:
fromList = foldMap singleton
这允许,例如:
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
我不知道任何一般的> import qualified Data.Vector as V
> foo [(+1),(+2),(+3)] (V.fromList [5,6,7])
[8,8,8]
>
。
我会写具体版本,或者最多概括一下输入类型。以下是fromList
的例子,忽略了Vector
已经存在。
Data.Vector.zip
你可以在第二个例子中使用import qualified Data.Vector as V
import Data.Vector (Vector)
import Data.Foldable
import GHC.Exts (IsList(fromList))
zipV1 :: Vector (a -> b) -> Vector a -> Vector b
zipV1 fs as = V.fromList (zipWith ($) (V.toList fs) (V.toList as))
zipV2 :: (Foldable f, Foldable g, IsList (f b)) => f (a -> b) -> g a -> f b
zipV2 fs as = fromList (zipWith ($) (toList fs) (toList as))
而不是IsList
。