无法从上下文中推断出来

时间:2015-07-19 12:56:08

标签: haskell types ghc typeclass

我有这种类型。但它无法推断出从goal等于isGoal的第一个变量类型返回的类型。如何解决这个问题?

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
class Problem p where 
    type State p :: * 
    data Action p :: * 

    goal :: Eq (State p) => State p 
    goal = undefined 

    isGoal :: Eq (State p) => State p -> Bool 
    isGoal s = s == goal 

结束这样做

class Problem p where 
    type State p :: * 
    data Action p :: * 

    goal :: p -> State p 
    goal = undefined 

    isGoal :: Eq (State p) => p -> State p -> Bool 
    isGoal p s = s == goal p

1 个答案:

答案 0 :(得分:8)

提示就在错误信息中:

  

N.B。:“州”是一种类型函数,可能不是单射的

这意味着什么:injective function f 是一个函数,其中来自 f x )= f < / em>( y )它遵循 x = y 。现在,我们在这里讨论类型级别,所以如果State是单射的,那么它将来自State p ~ State q p ~ q

s == goal中,编译器知道需要将goals统一起来(因为==总是比较相同类型的值),所以我们有:

s :: State p
goal :: State q
State p ~ State q

但由于State 不是 injective,编译器无法推断出p ~ q,即我们只讨论类型类的单个实例。

为什么不呢?好吧,你可以想出:

instance Problem Int where
  type State Int = Bool
  goal = True

instance Problem Double where
  type State Double = Bool
  goal = False

现在我们有State Int ~ State Double。然而,IntDouble显然不是同一类型,它们以相互矛盾的方式定义goal

“如何解决这个问题” - 好吧,你需要重新设计课程。

  • 您可以使用

    class Problem p where 
      data State p :: * 
    

    在这种情况下,State 是单射的,因为每个实例都需要硬编成单个instance Problem

  • 如果您需要能够在其他地方定义实际的State类型,则需要为编译器提供一个明确的提示,p应该用于goal。通常的解决方案是代理或 - 首选IMO - tagged值:

    {-# LANGUAGE ScopedTypeVariables #-}
    import Data.Tagged
    
    class Problem p where 
      type State p :: * 
    
      goal :: Eq (State p) => Tagged p (State p)
      goal = Tagged undefined
    
      isGoal :: Eq (State p) => Tagged p (State p) -> Bool 
      isGoal = isGoalDef
    
    isGoalDef :: forall p . Eq (State p) => Tagged p (State p) -> Bool 
    isGoalDef (Tagged s) = s == g
        where (Tagged g) = goal :: Tagged p (State p)