我正在尝试编写一个相当多态的库。我遇到了一个比说更容易展示的情况。它看起来有点像这样:
{-# 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
s。还有许多Formattable
对象,它们知道如何响应一堆不同的格式选项(这里简化为name
)。
它们Formattables
以多种方式组成,并且可以响应许多不同的目标。s 本质上是和Formatter
之间的路由器——给定一个目标(来自特定格式),它们以合适的对象响应。Format
Formattable
Formattable
这一切都很抽象。这是一个例子:
DateFormat
指定目标,如Year
、Month
和Day
。MonthType
是一种Formattable
新类型Int
,其名称如“二月”- 还有简单的
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.
而且我一生都无法弄清楚为什么。我究竟做错了什么?