aff-ify 在错误和成功回调中具有不同结果类型的函数
aff-ify a function that has different resulting types in error and success callback
让我们先看看 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)
这为我提供了最后一个函数的 'infinite type error'。我猜是因为这里的错误回调和成功回调不共享相同的结果类型,但我找不到办法解决这个问题。
编辑
看完接受的答案后,解决方案是:
runWebGLAff arg = makeAff (\err ok -> runWebGL arg (error >>> err) (unsafeCoerceEff <<< ok))
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
是它自己定义的一部分。又名 "infinite type"。这就是您收到错误的原因。
现在,为了修复它,您必须将参数 err
作为 Eff (webgl | eff) a
(根据 makeAff
类型的要求),但将其传递给 runWebGL
as 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)
P.S。通常我会建议切换到 PS 0.12,但似乎你不能那样做,因为 WebGL 库还没有更新(还没有?)。
让我们先看看 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)
这为我提供了最后一个函数的 'infinite type error'。我猜是因为这里的错误回调和成功回调不共享相同的结果类型,但我找不到办法解决这个问题。
编辑
看完接受的答案后,解决方案是:
runWebGLAff arg = makeAff (\err ok -> runWebGL arg (error >>> err) (unsafeCoerceEff <<< ok))
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
是它自己定义的一部分。又名 "infinite type"。这就是您收到错误的原因。
现在,为了修复它,您必须将参数 err
作为 Eff (webgl | eff) a
(根据 makeAff
类型的要求),但将其传递给 runWebGL
as 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)
P.S。通常我会建议切换到 PS 0.12,但似乎你不能那样做,因为 WebGL 库还没有更新(还没有?)。