类型家庭类型的黑客

我试图写一个相当多态的库。 我遇到了一个比告诉更容易展现的情况。 它看起来有点像这样:

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Map (Map)
import qualified Data.Map as Map

class Format f where type Target f
class Format f => Formatter x f where
  target :: forall y. Formatable y => Target f -> x -> y
class Formatable y where name :: y -> String

instance Formatable Integer where name = show
instance Formatable Int where name = show

split :: forall x f. (Format f, Formatter x f) => x -> f -> String -> [Either String (Target f)]
split = undefined

display :: forall x f. (Format f, Formatter x f) => f -> String -> x -> String
display f str x = let
  chunks = split x f str
  built = foldr apply "" chunks
  apply (Left s) accum = accum ++ s
  apply (Right t) accum = accum ++ name (target t x)
  in foldr apply "" chunks

基本上,我们有多态Format s,它定义了多个Target 。 还有一些Formattable对象,它们知道如何响应一堆不同的格式选项(这里简化为简单的name )。

这些Formattables以各种方式组成,并且可以响应多个不同的目标。 Formatter器本质上是FormatFormat Formattable之间的路由器 - 给定目标(来自特定格式),他们用合适的格式Formattable对象进行响应。

这是非常抽象的。 这是一个例子:

  • DateFormat指定YearMonthDay等目标。
  • MonthTypeInt一个Formattable ,其名称如“February”
  • 还有简单的instance Formattable Int where name = show
  • DateTime可能是(Int, MonthType, Int)类型的同义词。
  • (显然,我已经在这里删除了很多机器,比如给出正确的值,但你明白了。)

    display功能相当简单。 它需要格式化程序,指定格式的字符串,要显示的对象,并将其全部渲染为字符串。

    首先它将字符串分解成目标和字符串。 例如,日期格式化程序可能会将字符串"%Y-%m-%d"分解为[Right Year, Left "-", Right Month, Left "-", Right Day]split功能就是这样做的,并且已经在这里进行了编辑。

    display功能简单地追寻的Formattable S代表每个目标和累积的字符串。

    或者至少,它应该是。

    但是它没有通过以下错误进行类型检查:

    Reduced.hs:20:16:
        Could not deduce (Target f ~ Target f0)
        from the context (Format f, Formatter x f)
          bound by the type signature for
                     display :: (Format f, Formatter x f) => f -> String -> x -> String
          at Reduced.hs:(19,5)-(24,30)
        NB: `Target' is a type function, and may not be injective
        Expected type: [Either [Char] (Target f0)]
          Actual type: [Either String (Target f)]
        In the return type of a call of `split'
        In the expression: split x f str
        In an equation for `chunks': chunks = split x f str
    Failed, modules loaded: none.
    

    我不能为了我的生活找出原因。 我究竟做错了什么?


    问题是Target f不确定f ,这意味着函数

    target :: (Formatter f x, Formatable y) => Target f -> x -> y
    

    永远不会被调用。 不管你给什么类型的注解target ,你不能明确什么f是,所以编译器不能找出哪些Formatter使用实例。 我不是100%确定的,但可能解决方案不是使用多参数类型类,而是让xf中的一个成为另一个的函数。 另外,你应该完全删除Format类(你知道你不需要类来使用类型族吗?)。 也许是这样的:

    class Formatter x where
        type Format x
        target :: Formatable y => Format x -> x -> y
    
    链接地址: http://www.djcxy.com/p/78243.html

    上一篇: Type Family Type Hackery

    下一篇: Functional Dependencies / Type Families