gpt4 book ai didi

haskell - 有没有办法缩短这个派生条款?

转载 作者:行者123 更新时间:2023-12-04 07:32:52 27 4
gpt4 key购买 nike

有没有办法编写以下内容:

 {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveAnyClass #-}

data X = A | B | C
deriving (Eq, Ord, Show, Read, Data, SymWord, HasKind, SMTValue)

这样 deriving子句可以以某种方式缩短,如下所示:
 data X = A | B | C deriving MyOwnClass

如果可能的话,我想避免使用 TH,并且我很高兴创建一个新类,根据需要将所有这些派生类作为其父类(super class)(如上面的 MyOwnClass 中所示),但这并不是真的与 deriving 合作机制。通过约束种类扩展,我发现你可以这样写:
type MyOwnClass a = (Eq a, Ord a, Show a, Read a, Data a, SymWord a, HasKind a, SMTValue a)

不幸的是,我不能把它放在 deriving条款。有什么魔法可以让这一切发生吗?

编辑 从评论来看,似乎 TH 可能是这里唯一可行的选择。 (CPP 宏真的不行!)如果是这样,TH 解决方案的草图将会很高兴看到。

最佳答案

有坏而简单的方法,也有好的但困难的方法。如Silvio Mayolo说你可以用TemplateHaskell写这样的功能。这种方式是困难且相当复杂的方式。更简单的方法是像这样使用 C 预处理器:

{-# LANGUAGE CPP #-}

#define MY_OWN_CLASS (Eq, Ord, Show, Read, Data, SymWord, HasKind, SMTValue)

data X = A | B | C
deriving MY_OWN_CLASS

更新 (17.07.2016): TH 解决方案的想法和草图

在介绍解决方案草图之前,我将说明为什么使用 TH 更难做到这一点。 deriving -clause 不是一些独立的子句,它是 data 的一部分声明,因此您不能仅对 deriving 内的部分进行编码很遗憾。编写任何 TH 代码的一般方法是使用 runQ括号中的命令以查看最后应该写什么。像这样:
ghci> :set -XTemplateHaskell
ghci> :set -XQuasiQuotes
ghci> import Language.Haskell.TH
ghci> runQ [d|data A = B deriving (Eq, Show)|]
[ DataD
[]
A_0
[]
Nothing
[ NormalC B_1 [] ]
[ ConT GHC.Classes.Eq , ConT GHC.Show.Show ]
]

现在您看到 deriving 的类型类被指定为 DataD 的最后一个参数— 数据声明 — 构造函数。您的问题的解决方法是使用 -XStadandaloneDeriving extension .就像 deriving但功能强大,但也很冗长。同样,要查看您想要生成的内容,只需使用 runQ :
ghci> data D = T
ghci> :set -XStandaloneDeriving
ghci> runQ [d| deriving instance Show D |]
[ StandaloneDerivD [] (AppT (ConT GHC.Show.Show) (ConT Ghci5.D)) ]

您可以使用 StandaloneDerivD和其他构造函数直接或只使用 [d|...|] -括号虽然他们有更多的魔力,但他们给你列表 Dec (声明)。如果要生成多个声明,则应编写如下函数:
{-# LANGUAGE TemplateHaskell    #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-}

module Deriving where

import Language.Haskell.TH

boilerplateAnnigilator :: Name -> Q [Dec]
boilerplateAnnigilator typeName = do
let typeCon = conT typeName
[d|deriving instance Show $(typeCon)
deriving instance Eq $(typeCon)
deriving instance Ord $(typeCon)
|]

简要教程 can be found here .

然后你可以在另一个文件中使用它(这是称为阶段性限制的 TH 限制:你应该在一个文件中定义宏,但不能在同一个文件中使用它),如下所示:
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}

import Deriving

data X = A | B | C

boilerplateAnnigilator ''X

你应该把你想要的其他类型类放在 boilerplateAnnigilator 里面。功能。但这种方法只适用于非参数化类。如果您有 data MyData a = ...那么独立派生应该如下所示:
deriving instance Eq a => MyData a

如果您希望您的 TH 宏也适用于参数化类,那么您基本上应该通过推断类型是否具有类型变量并根据它生成实例来实现 GHC 编译器的整个逻辑。但这要困难得多。我认为最好的解决方案是在 GHC 编译器中制作票证,并让作者实现这种称为派生别名的功能:)

关于haskell - 有没有办法缩短这个派生条款?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45113205/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com