【问题标题】:Automatic haskell deriving declaration that lifts提升的自动haskell派生声明
【发布时间】:2016-03-21 09:42:01
【问题描述】:

有没有办法让编译器派生我手动编写的功能:

instance Class c => Class (Trans c) where
    foo1 = lift foo1
    foo2 = lift foo2
    ...
    foo999 = lift foo999
    bar1 = \a b c -> lift $ bar1 a b c
    ...
    baz1 = lift . baz1
    ...

即当一类Class 被包裹在Trans 中时,是否可以自动为Trans 获得Class 的免费实例,而无需进行繁重的工作:)?

【问题讨论】:

  • 我不确定我是否理解您真正想要的。该实例将适用于所有c,因此您只需编写一次。在一般情况下,我认为它不能再短了。
  • 但是这个实例很无聊(它只是提升了所有功能),也许可以简洁地写这个(不必枚举所有fooX = lift fooX等)
  • 我明白了,但是任何替代方案(例如 Template Haskell)看起来都更糟,除非你真的有大量的类方法。
  • 如果你有足够的类方法来证明 Template Haskell 的合理性,你应该考虑重新设计你的类。
  • 我不确定我是否遵循这个;你在找GeneralizedNewtypeDeriving吗? downloads.haskell.org/~ghc/7.8.4/docs/html/users_guide/…

标签: haskell typeclass deriving


【解决方案1】:

如果lift 本身是一个类型类函数,您可以为该类型类的所有实例编写一个通用定义。比如:

instance (Class c, Trans t) => Class (t c)

请注意,这不会与任何其他实例重叠,并且是所有这些类型所需的。

作为一个更完整的示例,此代码有效,尽管其结果有时令人惊讶。

{-# LANGUAGE FlexibleInstances #-}

module Inst where

import Control.Applicative (liftA2)

instance (Applicative f, Num n) => Num (f n) where
  (+) = liftA2 (+)
  (*) = liftA2 (*)
  abs = fmap abs
  signum = fmap signum
  fromInteger = pure . fromInteger
  negate = fmap negate

【讨论】:

  • 为某事物应用类型变量编写实例几乎从不是正确的方法,所以我不特别喜欢它作为建议。
  • 我实际上需要一个特定实例用于最底部的变压器,我只会在其余的变压器中使用提升。
猜你喜欢
  • 2012-10-02
  • 2012-12-28
  • 2015-02-21
  • 2011-04-02
  • 1970-01-01
  • 2016-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多