无法从上下文中推断出来

Dul*_*gon 0 haskell types typeclass ghc

我有这种类型.但它无法推断出从goalequals 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 
Run Code Online (Sandbox Code Playgroud)

结束这样做

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
Run Code Online (Sandbox Code Playgroud)

lef*_*out 8

提示就在错误消息中:

       注意:'状态'是一种类型函数,可能不是单射的

这意味着什么:内射函数 f是一个函数,其中从f(x)= f(y)得到x = y.现在,我们在这里谈论类型级别,所以如果State是单独的,那么它将遵循State p ~ State q这一点p ~ q.

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

s :: State p
goal :: State q
State p ~ State q
Run Code Online (Sandbox Code Playgroud)

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

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

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

instance Problem Double where
  type State Double = Bool
  goal = False
Run Code Online (Sandbox Code Playgroud)

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


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

  • 您可以使用

    class Problem p where 
      data State p :: * 
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    {-# 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)
    
    Run Code Online (Sandbox Code Playgroud)