haskell - 基于两个不同函子的应用类型类
问题描述
有没有类似于Applicative
类型类的东西,但是应用程序的每一端都有两个不同的函子?
IE(<*>) :: (Functor f, Functor g) => f (a -> b) -> g a -> f b
解决方案
(根据@dfeuer 在评论中的建议。)
有一种称为日卷积的结构,可让您在执行应用运算时保留两个函子之间的区别,并延迟将一个函子转换为另一个函子的时刻。
该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
为 aZipList
并折叠Day
:
res' :: ZipList (Char,Char)
res' = dap $ trans2 (ZipList . toList) res
ghci> res'
ZipList {getZipList = [('b','f'),('a','o')]}
可能的性能问题:当我们将一个函子提升到Day
时,另一个被赋予一个虚拟pure ()
值。Day
但是当将s 与结合起来时,这是自重的(<*>)
。通过将函子包装在Lift
转换器中,可以更智能地工作,从而为简单的“纯”案例获得更快的操作。
推荐阅读
- php - 如何将类似子查询的参数发送到 SQL 过程中?
- javascript - 如何在map api javascript中实时跟踪从firebase创建的标记
- php - 为什么我在使用 SendGrid API 发送电子邮件后在错误消息末尾收到空数组?
- python - 数据框到 nxn 矩阵
- javascript - 如何正确选择所有复选框?
- cookies - Cookie 标头必须以分号结尾且没有空格吗?
- forms - 在离线 Xamarin Forms 应用程序中验证密码
- c# - 使用自定义数据注释进行不显眼的验证不起作用
- azure - 如何从 Azure Devops 中的另一个管道有条件地运行一个管道?
- android-studio - 使用 Android Studio 为旧平台编写代码