假设,我有一个LangL r a
中具有计算功能的DSL。我可能想让函数与常量(0 :: Int
,"lala" :: String
)和DSL表达式(LangL r a
)一起使用。因此,我实现了一个类型类。但是,以任何方式尝试实现它,我都会遇到问题。
这是使用类型族时出现问题的最小示例:
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
data LangL r a = LangL a
deriving instance Functor (LangL r)
deriving instance Applicative (LangL r)
class DSLEntity r a where
type ValueOf a
entityValue :: a -> LangL r (ValueOf a)
instance DSLEntity r (LangL r a) where
type ValueOf (LangL r a) = a
entityValue = id
instance DSLEntity r Int where
type ValueOf Int = Int
entityValue = pure
foo :: LangL r Int -> LangL r Int
foo m = entityValue (entityValue m)
GHC提供以下输出:
• Ambiguous type variable ‘r0’ arising from a use of ‘entityValue’
prevents the constraint ‘(DSLEntity
r (LangL r0 Int))’ from being solved.
Relevant bindings include
m :: LangL r Int (bound at temp.hs:25:5)
foo :: LangL r Int -> LangL r Int
(bound at temp.hs:25:1)
Probable fix: use a type annotation to specify what ‘r0’ should be.
These potential instance exist:
instance DSLEntity r (LangL r a)
-- Defined at temp.hs:16:10
• In the expression: entityValue (entityValue m)
In an equation for ‘foo’: foo m = entityValue (entityValue m)
|
temp.hs:25:22-34: error: …
• Ambiguous type variable ‘r0’ arising from a use of ‘entityValue’
prevents the constraint ‘(DSLEntity
r0 (LangL r Int))’ from being solved.
Relevant bindings include
m :: LangL r Int (bound at temp.hs:25:5)
foo :: LangL r Int -> LangL r Int
(bound at temp.hs:25:1)
Probable fix: use a type annotation to specify what ‘r0’ should be.
These potential instance exist:
instance DSLEntity r (LangL r a)
-- Defined at /temp.hs:16:10
• In the first argument of ‘entityValue’, namely ‘(entityValue m)’
In the expression: entityValue (entityValue m)
In an equation for ‘foo’: foo m = entityValue (entityValue m)
|
问题很明显。 r
的LangL r a
参数与r
的DSLEntity
参数之间没有依赖关系。但是,我们无法添加此类依赖项,因为对于Int
实例,它实际上不存在。
我很困惑,想知道是否有可能完成我想做的事情。如果没有,为什么?
我认为您只需要为GHC提供一些有关中间类型的帮助:
{-# LANGUAGE ScopedTypeVariables #-}
foo :: forall r. LangL r Int -> LangL r Int
foo m = entityValue (entityValue m :: LangL r Int)
正如您所写,r
的a
和DSLEntity
参数之间确实没有依赖关系。因此,为了表示r
(DSLEntity r
的参数)等于r
(LangL r
的参数),我们使用等式~
。
instance r1 ~ r2 => DSLEntity r1 (LangL r2 a) where ...
您可以使用: