修复HLists中的类型推断问题

3

我一直在尝试编译一些代码。它的作用是取出一个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

很遗憾,当我尝试编译它时,会给出以下错误:

    No instance for (ApplyAB HConcat2 ([Char], [Char]) r2)
      arising from a use of ‘hFoldr’
    The type variable ‘r2’ is ambiguous
    Note: there is a potential instance available:
      instance ApplyAB HConcat2 (String, String) String
        -- Defined at src/Web/Rusalka/Condition.hs:274:10
    In the expression: hFoldr HConcat2 "Result: " x
    In an equation for ‘y’: y = hFoldr HConcat2 "Result: " x

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

1个回答

2

ApplyAB类没有功能依赖,因此当GHC尝试选择一个实例时,输入类型无法确定结果类型。在这种情况下,会导致hFoldr链中的所有中间类型变得模糊不清,GHC不知道选择哪个实例。

为了解决这个问题,您可以使用一个技巧,在实例头中完全保持结果类型的一般性,并使用等式~约束来限制它,在GHC选择实例之后(只有实例头用于选择)。

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

使用这种方法(并添加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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接