为什么`coerce`无法隐式为`liftA3`参数自动应用`Compose`包装?
报错的核心原因
coerce工作的前提是编译器能明确推断出需要相互转换的两个类型的内存表示完全一致,你写的coerce liftA3 Vec3 getX getY getZ无法通过编译,本质是类型推断信息不足:
coerce是左结合运算,你写的表达式等价于((((coerce liftA3) Vec3) getX) getY) getZ,编译器处理coerce liftA3时还没有足够的上下文信息确定要把liftA3转成什么类型,只能得到一堆无约束的类型变量f0/c0,自然无法匹配到你期望的Compose ((->) Input) Maybe Int和Input -> Maybe Int的转换关系。- 你之前写的
coerce ((+) :: Int -> Int -> Int) (Max (5::Int)) (Min (8::Int)) :: Sum Int能正常工作,是因为你给源函数(+)加了明确类型签名,还指定了整个表达式的返回类型,编译器可以清晰推导所有需要转换的类型对,验证Coercible约束成立。
如果你一定要直接对liftA3做coerce,只要补全足够的类型信息就能通过编译:
v3''' :: Input -> Maybe Vec3 v3''' = getCompose go where go = (coerce (liftA3 :: (Int -> Int -> Int -> Vec3) -> Compose ((->) Input) Maybe Int -> Compose ((->) Input) Maybe Int -> Compose ((->) Input) Maybe Int -> Compose ((->) Input) Maybe Vec3) ) Vec3 getX getY getZ
只是这种写法比分别coerce三个参数还要冗余,没有实用价值。
更简洁的写法
针对你的场景,用applicative组合的写法更直观:
import Data.Functor.Compose v3 :: Input -> Maybe Vec3 v3 = getCompose $ Vec3 <$> Compose getX <*> Compose getY <*> Compose getZ
内容的提问来源于stack exchange,提问作者amalloy
相关产品推荐
相关产品推荐

