约束条件的别名不与上下文共享相同的变量绑定行为

时间:2015-09-26 22:31:38

标签: haskell constraints type-families type-variables

我一直在玩-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带到顶级范围之外,还有解决方法吗?

1 个答案:

答案 0 :(得分:6)

没有真正的不一致,只是

  1. 类型签名中的自由类型变量会自动添加forall个量词,因此第一种情况实际上等同于

    foo :: forall callTree output input. ( callTree ~ SomeTypeFunc output
           , OtherTypeFunc input ~ callTree
           ) => input -> output
    
  2. type声明右侧的所有自由类型变量必须是参数,不能包含任何不在范围内的变量。

  3. 这不是特定于约束种类,除了您不能将forall量词直接应用于约束的不幸事实,这意味着我不知道一般变通方法使这种约束类型声明工作。

    在您的特定示例中,( 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