Applicative typeclass based on two different functors

Nea*_*der 3 haskell functor applicative

Is there something similar to the Applicative type class, but where there are two functors for each side of the application which are different?

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

dan*_*iaz 5

(在评论中来自@dfeuer的建议。)

有一种称为“ 日卷积”的构造,可让您在执行应用操作时保留两个函子之间的区别,并延迟将一个函子转换为另一个函子的时间。

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

data Day f g a = forall b c. Day (f b) (g c) (b -> c -> a)
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

Nat2来自fin包,用于Vecvec参数化固定大小。)

我们可以将它们压缩在一起:

res :: Day ZipList (Vec Nat2) (Char,Char)
res = (,) <$> day1 <*> day2
Run Code Online (Sandbox Code Playgroud)

然后将转换VecZipList并折叠Day

res' :: ZipList (Char,Char)
res' = dap $ trans2 (ZipList . toList) res

ghci> res'
ZipList {getZipList = [('b','f'),('a','o')]}
Run Code Online (Sandbox Code Playgroud)

使用daptrans2功能。

可能的性能问题:当我们将一个函子提升到时Day,另一个函子将被赋予一个虚拟pure ()值。但这是将Days与组合时的净重(<*>)。通过将函子包装在Lift变压器中,可以使工作更智能,从而在简单的“纯”情况​​下获得更快的运行速度。