是否可以为DSL中的常量和表达式都提供类型类?

问题描述 投票:0回答:3

假设,我有一个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)
   |

问题很明显。 rLangL r a参数与rDSLEntity参数之间没有依赖关系。但是,我们无法添加此类依赖项,因为对于Int实例,它实际上不存在。

我很困惑,想知道是否有可能完成我想做的事情。如果没有,为什么?

haskell dsl functional-dependencies type-families
3个回答
1
投票

我认为您只需要为GHC提供一些有关中间类型的帮助:

{-# LANGUAGE ScopedTypeVariables   #-}

foo :: forall r. LangL r Int -> LangL r Int
foo m = entityValue (entityValue m :: LangL r Int)

0
投票

正如您所写,raDSLEntity参数之间确实没有依赖关系。因此,为了表示rDSLEntity r的参数)等于rLangL r的参数),我们使用等式~

instance r1 ~ r2 => DSLEntity r1 (LangL r2 a) where ...
    

0
投票

您可以使用:

© www.soinside.com 2019 - 2024. All rights reserved.