约束的类型别名与上下文不共享相同的变量绑定行为
Type Aliases for Constraints don't share the same variable binding behavior as Contexts
我一直在研究 -XConstraintKinds
来帮助缓解过于冗长的上下文,并且发现了变量绑定方面的一个有趣的不一致:
{-# LANGUAGE
TypeFamilies
, ConstraintKinds
, FlexibleContexts
#-}
-- works
foo :: ( callTree ~ SomeTypeFunc output
, OtherTypeFunc input ~ callTree
) => input -> output
type FooCtx input output =
( callTree ~ SomeTypeFunc output
, OtherTypeFunc input ~ callTree
)
-- doesn't work
foo' :: FooCtx input output =>
input -> output
除了将 callTree
置于顶级范围之外,是否有解决此问题的方法?
没有真正的不一致,只是
类型签名中的自由类型变量自动添加了forall
个量词,所以第一种情况实际上等同于
foo :: forall callTree output input. ( callTree ~ SomeTypeFunc output
, OtherTypeFunc input ~ callTree
) => input -> output
type
声明右侧的所有自由类型变量都必须是参数,不能有任何不在范围内的变量。
这不是特定于约束类型的,除了你不能将 forall
量词直接应用于约束的不幸事实,这意味着我不知道 general 使此类约束类型声明起作用的解决方法。
在您的特定示例中,( OtherTypeFunc input ~ SomeTypeFunc output )
应该是等效的,但我假设您真的对这样的重写不起作用的更复杂的示例感兴趣。
我可以想到一种不同的解决方法,通过在约束右侧包含值,以不同的方式将参数更改为类型声明:
{-# LANGUAGE TypeFamilies, ConstraintKinds, FlexibleContexts, RankNTypes #-}
type family OtherTypeFunc a
type family SomeTypeFunc a
type FooCtx input output value =
forall callTree. ( callTree ~ SomeTypeFunc output
, OtherTypeFunc input ~ callTree
) => value
-- This now works
foo' :: FooCtx input output ( input -> output )
foo' = undefined
我一直在研究 -XConstraintKinds
来帮助缓解过于冗长的上下文,并且发现了变量绑定方面的一个有趣的不一致:
{-# LANGUAGE
TypeFamilies
, ConstraintKinds
, FlexibleContexts
#-}
-- works
foo :: ( callTree ~ SomeTypeFunc output
, OtherTypeFunc input ~ callTree
) => input -> output
type FooCtx input output =
( callTree ~ SomeTypeFunc output
, OtherTypeFunc input ~ callTree
)
-- doesn't work
foo' :: FooCtx input output =>
input -> output
除了将 callTree
置于顶级范围之外,是否有解决此问题的方法?
没有真正的不一致,只是
类型签名中的自由类型变量自动添加了
forall
个量词,所以第一种情况实际上等同于foo :: forall callTree output input. ( callTree ~ SomeTypeFunc output , OtherTypeFunc input ~ callTree ) => input -> output
type
声明右侧的所有自由类型变量都必须是参数,不能有任何不在范围内的变量。
这不是特定于约束类型的,除了你不能将 forall
量词直接应用于约束的不幸事实,这意味着我不知道 general 使此类约束类型声明起作用的解决方法。
在您的特定示例中,( OtherTypeFunc input ~ SomeTypeFunc output )
应该是等效的,但我假设您真的对这样的重写不起作用的更复杂的示例感兴趣。
我可以想到一种不同的解决方法,通过在约束右侧包含值,以不同的方式将参数更改为类型声明:
{-# LANGUAGE TypeFamilies, ConstraintKinds, FlexibleContexts, RankNTypes #-}
type family OtherTypeFunc a
type family SomeTypeFunc a
type FooCtx input output value =
forall callTree. ( callTree ~ SomeTypeFunc output
, OtherTypeFunc input ~ callTree
) => value
-- This now works
foo' :: FooCtx input output ( input -> output )
foo' = undefined