我有这种类型。但它无法推断出从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
答案 0 :(得分:8)
提示就在错误信息中:
N.B。:“州”是一种类型函数,可能不是单射的
这意味着什么:injective function f 是一个函数,其中来自 f ( x )= f < / em>( y )它遵循 x = y 。现在,我们在这里讨论类型级别,所以如果State
是单射的,那么它将来自State p ~ State q
p ~ q
。
在s == goal
中,编译器知道需要将goal
与s
统一起来(因为==
总是比较相同类型的值),所以我们有:
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
。然而,Int
和Double
显然不是同一类型,它们以相互矛盾的方式定义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)