无法从上下文推断

Could not deduce from the context

我有这种class。但它不能推断出从 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

提示就在错误消息中:

       N.B.: ‘State’ is a type function, and may not be injective

这意味着什么:injective function f 是一个函数,其中 from f(x) = f(y) 因此 x = y。现在,我们在这里讨论的是类型级别,所以如果 State 是单射的,那么从 State p ~ State q 可以得出 p ~ q.

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

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

但是因为 State 不是 不是 单射的,编译器不能推断出 p ~ q,即我们只是在谈论单个实例class.

类型

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

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。

  • 可以使用

    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)