在错误和成功回调中具有不同结果类型的函数

问题描述 投票:0回答:1

让我们首先看一下web-gl包中的类似函数,其意图是:

withShaders
  :: forall bindings eff a
   . Shaders ({ | bindings }) -> (String -> EffWebGL eff a) -> ({ webGLProgram :: WebGLProg | bindings } -> EffWebGL eff a) -> EffWebGL eff a


makeAff
  :: forall e a
   . ((Error -> Eff e Unit) -> (a -> Eff e Unit) -> Eff e Unit) -> Aff e a


withShadersAff :: forall eff a. Shaders { | a } -> Aff ( webgl ∷ WebGl | eff ) { webGLProgram ∷ WebGLProg | a }
withShadersAff arg = makeAff (\err ok -> withShaders arg (error >>> err) ok)

这基本上将基于withShaders函数的回调转换为可以在aff上下文中使用的函数。

我想知道为什么,同样的事情不适用于以下函数(也来自webgl包):

runWebGL :: forall a eff. String -> (String -> Eff eff a) -> (WebGLContext -> EffWebGL eff a) -> Eff eff a


runWebGLAff :: forall eff . String -> Aff ( webgl ∷ WebGl | eff ) WebGLContext
runWebGLAff arg = makeAff (\err ok -> runWebGL arg (error >>> err) ok)

这给了我最后一个函数的“无限类型错误”。我想这是因为这里错误回调和成功回调不共享相同的结果类型,但我找不到解决这个问题。


编辑

阅读接受的答案后,解决方案是:

runWebGLAff arg = makeAff (\err ok -> runWebGL arg (error >>> err) (unsafeCoerceEff <<< ok))
purescript
1个回答
0
投票

EffWebGL定义如下in the library

type EffWebGL eff a = Eff (webgl :: WebGl | eff) a

它只是Eff的别名,但请注意其效果行包括WebGl效果。

当编译器试图在你的函数中调和它时,它会从使用ok作为回调推导出ok :: Eff (webgl | eff) a,但由于ok回调必须与错误回调具有相同的类型(来自makeAff的签名),编译器也推断出err :: Eff (webgl | eff) a,因此,error >>> err :: Eff (webgl | eff) a。然而,由于error >>> err被用作runWebGL的参数,它意味着error >>> err :: Eff eff a(这就是runWebGL的定义)。所以编译器现在有两条信息必须是真的:

(1)  error >>> err :: Eff (webgl | eff) a
(2)  error >>> err :: Eff eff a

当然,这必须意味着(webgl | eff) === eff。所以eff是它自己定义的一部分。阿卡“无限型”。这就是你收到错误的原因。

现在,为了修复它,你必须将你的参数err作为Eff (webgl | eff) a(根据makeAff的类型的要求),但是将它作为runWebGL传递给Eff eff a(根据runWebGL的类型的要求) - 即效果行会变宽为它从内部回调流向外部。这应该是完全安全的,因为内部回调永远不会使用这种效果(如其类型所示),但是,编译器没有安全的方法来做到这一点 - 这可能是效果的原因之一在PureScript 0.12中丢弃了行(并且很好地解决了!)

相反,你必须使用类型不安全的方式from Control.Monad.Eff.Unsafe

unsafeCoerceEff :: forall eff1 eff2 a. Eff eff1 a -> Eff eff2 a

只需在对此函数的调用中包装错误回调,它就可以工作:

runWebGLAff arg = makeAff (\err ok -> runWebGL arg (unsafeCoerceEff $ error >>> err) ok)

附:通常我会建议切换到PS 0.12,但似乎你不能这样做,因为WebGL库还没有更新(但是?)。

© www.soinside.com 2019 - 2024. All rights reserved.