haskell - 定义部分应用的类型类

标签 haskell typeclass

探索 typeclasses are essentially C++ abstract classes without nested inheritance 的想法,我已经写了类型类

class Interface i c where
    i :: c -> i

instance Interface i i where i = id

infixl 1 #
(#) :: Interface i c => c -> (i -> r) -> r
c # f = f $ i c

使用类似的界面
data IDrawable' = IDrawable { draw :: IO () }

我想要类似的东西
type IDrawable c = Interface IDrawable' c

这样我就可以做到
data Object = Object { objectDraw :: IO () }
data Person = Person { personDraw :: IO () }

instance IDrawable Object where i = IDrawable . objectDraw
instance IDrawable Person where i = IDrawable . personDraw

type IDrawable cConstraintKinds 编译,我不允许做instance IDrawable Object where i = IDrawable . objectDraw有错误
'i' is not a (visible) method of class 'IDrawable`

有没有办法声明IDrawable c = Interface IDrawable' c以便它可以被实例化?

这纯粹是出于学术兴趣,我不建议任何人在实际应用中使用这种模式,我只是想知道这种事情是否可以不应用 TemplateHaskellCPP .

最佳答案

不,这是不可能的(从 7.8.3 开始,我认为也是 7.10);它是 GHC bug #7543 .这不是一个非常容易被贩卖的错误。显然,至少有少数人希望能够写出这种东西(例如,你,Edward Kmett),但大多数人都没有注意到这一点。跟踪器上记录的更改此行为没有任何进展。

至于为什么不能,让我解释一下 Simon Peyton-Jones 对 bug 跟踪器的解释。问题是类型检查实例有两个部分:首先,GHC 必须查找方法名称(这里是 i)的来源;其次,GHC 必须扩展类型同义词。由于这两个步骤在本期中由 GHC 的两个不同组件执行,因此不支持约束同义词实例; GHC 无法判断它需要查看哪个类才能找到 i .

这是一个错误的另一个原因——也是我发现这个的原因,根据 András Kovács's answer 上的评论——是不是当前的行为不像“它不起作用”那么简单。相反,它会尝试工作,但你不能声明任何方法……但你可以声明一个无方法的实例!在 GHCi 中:

GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
...
Prelude> :set -XMultiParamTypeClasses -XFlexibleInstances -XConstraintKinds
Prelude> class Interface i c where i :: c -> i
Prelude> instance Interface i i where i = id
Prelude> let (#) :: Interface i c => c -> (i -> r) -> r ; c # f = f $ i c ; infixl 1 #
Prelude> data IDrawable' = IDrawable { draw :: IO () }
Prelude> type IDrawable = Interface IDrawable'
Prelude> instance IDrawable () where i _ = IDrawable $ return ()

<interactive>:8:29:
    ‘i’ is not a (visible) method of class ‘IDrawable’
Prelude> ()#draw

<interactive>:9:3:
    No instance for (Interface IDrawable' ()) arising from a use of ‘#’
    In the expression: () # draw
    In an equation for ‘it’: it = () # draw
Prelude> instance IDrawable () where {}

<interactive>:10:10: Warning:
    No explicit implementation for
      ‘i’
    In the instance declaration for ‘Interface IDrawable' ()’
Prelude> ()#draw
*** Exception: <interactive>:10:10-21: No instance nor default method for class operation Ghci1.i

换句话说:
instance IDrawable () where i _ = IDrawable $ return ()

失败,但是
instance IDrawable () where {}

成功!很明显,检查需要放松或收紧,具体取决于所需的行为:-)

P.S.:还有一件事:你应该尽可能地 eta-reduce 类型同义词。这就是我更改 IDrawable 的原因至
type IDrawable = Interface IDrawable'

并删除了c GHCi 中两边的参数上面的代码。这样做的好处是,由于不能部分应用类型同义词,因此您无法通过 IDrawable 的版本。作为任何东西的参数;然而,完全 eta 减少的版本可以通过任何期望的东西 * -> Constraint .

(这在 András Kovács's answer 中有所提及,我在评论中提到了这一点;不过,由于我最终也写了一个答案,我想我也会在这里添加它。)

关于haskell - 定义部分应用的类型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29039526/

相关文章:

haskell - 为什么 Control.Arrow 中没有 Kleisli 的 Functor 实例?

algorithm - 一些有效的方法来实现这种 map 的插入和查找?

Haskell并发 channel : What is difference between this two codes?

Haskell:为什么 GHC 不使用fundeps 推断这个类型类中的类型?

haskell - 在类型化模板 Haskell 中使用约束

haskell - 由于 native 依赖项中的 "multiple definition"链接器错误,构建失败

haskell - 类型等式约束和多态性

haskell - 依赖类约束的不明确类型变量

Haskell 的类型系统将数值视为函数?

haskell - 我可以在不过分宽容的情况下自动为转换函数生成类型类实例吗?