ama*_*loy 8 haskell applicative
考虑这种类型:
\ndata Vec3 = Vec3 {_x, _y, _z :: Int}\nRun Code Online (Sandbox Code Playgroud)\n我有一些函数都采用相同的输入,并且可能无法计算字段:
\ndata Input\ngetX, getY, getZ :: Input -> Maybe Int\nRun Code Online (Sandbox Code Playgroud)\n我可以编写一个函数来尝试所有这三个字段构造函数:
\nv3 :: Input -> Maybe Vec3\nv3 i = liftA3 Vec3 (getX i) (getY i) (getZ i)\nRun Code Online (Sandbox Code Playgroud)\n但必须将输入传递i三次左右,这有点烦人。函数本身就是一个应用函子,因此可以替换foo x = bar (f x) (g x) (h x)为foo = liftA3 bar f g h。
在这里,我的bar是liftA3 Vec3,所以我可以写
v3' :: Input -> Maybe Vec3\nv3' = liftA3 (liftA3 Vec3) getX getY getZ\nRun Code Online (Sandbox Code Playgroud)\n但这有点恶心,当我们以这种方式(((->) Input)和Maybe)使用组合应用程序时,就会有Compose新类型来处理这种事情。有了它我就可以写
v3'' :: Input -> Maybe Vec3\nv3'' = getCompose go\n where go = liftA3 Vec3 x y z\n x = Compose getX\n y = Compose getY\n z = Compose getZ\nRun Code Online (Sandbox Code Playgroud)\n好吧,这并不是一个很好的字符节省,但我们现在使用一个组合函子而不是两个,这很好。我想我可以用coerce它来赢回一些角色:毕竟,x它只是一个新类型的包装器getX,对于其他字段也是如此。所以我想我可以强迫liftA3接受三个Input -> Maybe Vec3而不是接受三个Compose ((->) Input) Maybe Vec3:
v3''' :: Input -> Maybe Vec3\nv3''' = getCompose go\n where go = coerce liftA3 Vec3 getX getY getZ\nRun Code Online (Sandbox Code Playgroud)\n但这不起作用,会产生错误消息:
\ntmp.hs:23:14: error:\n \xe2\x80\xa2 Couldn't match representation of type \xe2\x80\x98f0 c0\xe2\x80\x99\n with that of \xe2\x80\x98Input -> Maybe Int\xe2\x80\x99\n arising from a use of \xe2\x80\x98coerce\xe2\x80\x99\n \xe2\x80\xa2 In the expression: coerce liftA3 Vec3 getX getY getZ\n In an equation for \xe2\x80\x98go\xe2\x80\x99: go = coerce liftA3 Vec3 getX getY getZ\n In an equation for \xe2\x80\x98v3'''\xe2\x80\x99:\n v3'''\n = getCompose go\n where\n go = coerce liftA3 Vec3 getX getY getZ\n |\n23 | where go = coerce liftA3 Vec3 getX getY getZ\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nRun Code Online (Sandbox Code Playgroud)\n我不明白为什么不。我可以写coerce getX :: Compose ((->) Input) Maybe Int,这很好。通常,可以强制函数以强制其参数或返回类型,如
coerce ((+) :: Int -> Int -> Int) (Max (5::Int)) (Min (8::Int)) :: Sum Int\nRun Code Online (Sandbox Code Playgroud)\n事实上我可以写出所有coerce单独写出所有的 s :
v3'''' :: Input -> Maybe Vec3\nv3'''' = getCompose go\n where go = liftA3 Vec3 x y z\n x = coerce getX\n y = coerce getY\n z = coerce getZ\nRun Code Online (Sandbox Code Playgroud)\n那么为什么不能liftA3强迫自己接受getX而不是coerce getX让我使用v3'''呢?
如果您向 提供适用函子liftA3,则进行以下类型检查:
v3' :: Input -> Maybe Vec3
v3' = coerce (liftA3 @(Compose ((->) Input) Maybe) Vec3) getX getY getZ
Run Code Online (Sandbox Code Playgroud)
在coerce liftA3没有任何注释的情况下,无法推断要使用什么应用函子liftA3。这些都没有提到类型Compose。它也可能是ReaderT Input Maybe另Kleisli Maybe Input一种具有非法实例或更奇特的类型。
在getCompose (coerce liftA3 _ _ _)(您的最后一次尝试)中,getCompose不约束liftA3( 的“内部” coerce),因为getCompose是 的“外部” coerce。它要求 的结果类型liftA3可强制为Compose ((->) Input) Maybe Vec3,但它可能仍然不等于 。