3

我一直在尝试编译一些代码。它的意思是采取 a HList,提取字符串并将它们连接在一起。


{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module Lib
    ( y
    ) where

import Data.HList

data HConcat2 = HConcat2
instance ApplyAB HConcat2 (String, String) String where
  applyAB _ (a,b) = a ++ b
instance ApplyAB HConcat2 (Int, String) String where
  applyAB _ (_,a) = a

x :: HList '[Int, String, Int, String]
x = 3 .*. "Hello" .*. 4 .*. " World" .*. HNil

y :: String
y = hFoldr HConcat2 "Result: " x

不幸的是,当我尝试编译它时,它给了我

    (ApplyAB HConcat2 ([Char], [Char]) r2) 没有实例
      由使用“hFoldr”引起
    类型变量“r2”不明确
    注意:有一个潜在的实例可用:
      实例 ApplyAB HConcat2 (String, String) 字符串
        -- 定义在 src/Web/Rusalka/Condition.hs:274:10
    在表达式中: hFoldr HConcat2 "结果:" x
    在 'y' 的等式中: y = hFoldr HConcat2 "结果:" x

我如何说服它使用我声明的实例?

4

1 回答 1

2

类没有函数依赖ApplyAB,因此当 GHC 尝试选择一个实例时,输入类型并不能确定结果类型。在这种情况下,这会导致hFoldr链中的所有中间类型变得不明确,并且 GHC 不知道要选择哪些实例。

为了解决这个问题,您可以使用一个技巧,将结果类型完全通用地保留在实例的头部,并在 GHC 选择实例~使用等式约束对其进行限制(仅实例的头部用于选择)。

如果你:i ApplyAB在 GHCi 中这样做,你会注意到几个预定义的实例使用了这样的等式约束。

使用这个(并添加TypeFamilies)使您的代码对我有用:

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}

module Lib
    ( y
    ) where

import Data.HList

data HConcat2 = HConcat2
instance s ~ String => ApplyAB HConcat2 (String, String) s where
  applyAB _ (a,b) = a ++ b
instance s ~ String => ApplyAB HConcat2 (Int, String) s where
  applyAB _ (_,a) = a

x :: HList '[Int, String, Int, String]
x = 3 .*. "Hello" .*. 4 .*. " World" .*. HNil

y :: String
y = hFoldr HConcat2 "Result: " x
于 2015-07-12T01:21:49.090 回答