无法从上下文推断
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
中,编译器知道它需要统一goal
和s
(因为==
总是比较相同类型的值),所以我们有它:
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
。然而显然 Int
和 Double
不是同一类型,它们以相互矛盾的方式定义 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)
我有这种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
中,编译器知道它需要统一goal
和s
(因为==
总是比较相同类型的值),所以我们有它:
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
。然而显然 Int
和 Double
不是同一类型,它们以相互矛盾的方式定义 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)