(如何)在“dependent-map”GADT中有多态值?

时间:2018-04-26 17:28:05

标签: haskell gadt reflex

任何人都知道如何/ this code可以延长Foo GADT:

{-# language GADTs #-}
{-# language DeriveGeneric #-}
{-# language DeriveAnyClass #-}
{-# language TemplateHaskell #-}
{-# language StandaloneDeriving #-}

import Prelude                  (Int, String, print, ($))
import Data.GADT.Show           ()
import Data.GADT.Compare        ()
import Data.Dependent.Map       (DMap, fromList, (!))
import Data.Dependent.Sum       ((==>))
import Data.GADT.Compare.TH     (deriveGEq, deriveGCompare)
import Data.Functor.Identity    (Identity)

data Foo a where
  AnInt   :: Foo Int
  AString :: Foo String

deriveGEq      ''Foo
deriveGCompare ''Foo

dmap1 :: DMap Foo Identity
dmap1 = fromList [AnInt ==> 1, AString ==> "bar"]

main = do
  print $ dmap1 ! AnInt
  print $ dmap1 ! AString

  -- Prints:
  -- Identity 1
  -- Identity "bar"

  ANum :: Num n => Foo n

(或类似的东西)允许dependent-map中的多态值?

当我尝试时,我得到类似的错误:

exp-dep-map.hs:20:1: error:
    • Couldn't match type ‘a’ with ‘b’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          geq :: forall a b. Foo a -> Foo b -> Maybe (a := b)
        at exp-dep-map.hs:20:1-20
      ‘b’ is a rigid type variable bound by
        the type signature for:
          geq :: forall a b. Foo a -> Foo b -> Maybe (a := b)
        at exp-dep-map.hs:20:1-20
      Expected type: Maybe (a := b)
        Actual type: Maybe (a :~: a)
    • In a stmt of a 'do' block: return Refl
      In the expression: do return Refl
      In an equation for ‘geq’: geq ANum ANum = do return Refl
    • Relevant bindings include
        geq :: Foo a -> Foo b -> Maybe (a := b)
          (bound at exp-dep-map.hs:20:1)
   |
20 | deriveGEq      ''Foo
   | ^^^^^^^^^^^^^^^^^^^^

编辑:我已经与echatav和isovector(GitHub用户名)一起继续努力,我们能够进一步解决这个问题,我们还发现定义GEq和{{1}用手帮助实例。谢谢你,@ rampion,你的回答也证实了我们所发现的。

虽然为大型记录类型手动定义这些并不理想。我想知道TemplateHaskell生成器(GComparederiveGCompare){是否需要}可以更新以处理多态性。

此外,我发现,对于我目前的用例,我正在寻找的pol实际上更接近

deriveGEq

手动定义实例也适用于此,而且不太理想。

data Foo n a where
  AnInt :: Foo n Int
  AString :: Foo n String
  ANum :: (Num n, Typeable n, Show n) => Foo n n

尝试使用TH,(例如instance GEq (Foo n) where geq AnInt AnInt = return Refl geq AString AString = return Refl geq ANum ANum = return Refl geq _ _ = Nothing instance GCompare (Foo n) where gcompare AnInt AnInt = GEQ gcompare AnInt _ = GLT gcompare _ AnInt = GGT gcompare AString AString = GEQ gcompare AString _ = GLT gcompare _ AString = GGT gcompare (ANum :: Foo n a) (ANum :: Foo n b) = (eqT @a @b) & \case Just (Refl :: a :~: b) -> GEQ Nothing -> error "This shouldn't happen" gcompare ANum _ = GLT gcompare _ ANum = GGT deriveGEq ''Foo)我遇到了问题。

deriveGEq ''(Foo n)

exp-dep-map.hs:39:1: error:
    • Expecting one more argument to ‘Foo’
      Expected kind ‘* -> *’, but ‘Foo’ has kind ‘* -> * -> *’
    • In the first argument of ‘GEq’, namely ‘Foo’
      In the instance declaration for ‘GEq Foo’
   |
39 | deriveGEq      ''Foo
   | ^^^^^^^^^^^^^^^^^^^^

也许相关:https://github.com/mokus0/dependent-sum-template/pull/6

1 个答案:

答案 0 :(得分:5)

模板haskell让我很难看到发生了什么,所以我建议你推出自己的GEq实例来更好地理解错误。

查看the definition of GEq

class GEq f where
  geq :: f a -> f b -> Maybe (a := b) 

我们对ab没有任何进一步的限制,所以我们需要单独证明(或反驳)GADT构造函数上的类型相等。

以上ANum未提供给我们。

如果我们向ANum添加另一个约束 - Typeable

,这是可以修复的
ANum :: (Num n, Typeable n) => n -> Foo n

现在我们可以使用eqT来见证类型相等

geq (ANum _) (ANum _) = eqT