Haskell:获取数据构造函数名称作为字符串

25

假设我们有

data D = X Int | Y Int Int | Z String

我希望能有一个名为getDConst的函数。

getDConst :: D -> String

根据输入的数据构造函数,返回“X”、“Y”或“Z”之一。有没有通用的方法可以在不必为每个数据构造函数都进行case的情况下编写此代码?(我可以接受依赖于 Data.Typeable 或类似东西的解决方案)

3个回答

26

我自己找到了解决方案,但是留下这个问题来帮助其他人:

import Data.Data
data D = X Int | Y Int Int deriving (Data,Typeable)

let result = show $ toConstr (X 3) -- result contains what we wanted

1
如果其他人也遇到了这个错误:尝试在文件开头添加 {-# LANGUAGE DeriveDataTypeable #-}。在 GHC 中,当您派生 Data 和 Typeable 时,这是必需的。 - jplatte
你也可以使用showConstr而不是show。它们的功能完全相同,但showConstr使用错误类型的风险较小。 - undefined

11

如果您不想使用Typeable,也可以使用Show来实现此操作。

getDConst :: D -> String
getDConst = head . words . show

Show 不会输出所有的字段,因为它是惰性的。你可以在 ghci 中运行以下代码进行测试:

Prelude> data D = D [Int] deriving (Show)
Prelude> getDConst $ D [1..]
"D"

您可能还想实现一个自定义的显示输出,而不涉及构造函数。 - kqr
1
show 是惰性求值的,所以这可能不会很慢。注意 take 5 (show (Just undefined)) 能够正常工作。 - Ben Millwood
3
你的意思是“单词”,而不是“非单词”。(实际上,我会写类似于takeWhile (/=' ') . show的代码)。 - Lynn
4
如果有人修改了默认的 show 实现方式,那么它将不能正常工作…这个解决方案依赖于一种约定。 - Nicolas Henin

-1

我对这个问题有一个非常基本的答案,不需要进行导入或其他操作。它只是一个简单的函数。

假设我有以下数据。数据定义中重复的 Int 是有意为之的,因为我之后会使用“不关心”符号:

data YES_NO_CANCEL = YES Int | NO Int Int | CANCEL Int Int Int

那么你可以创建一个函数:

extractDataType :: YES_NO_CANCEL -> String
extractDataType (YES _) = "YES"
extractDataType (NO _ _) = "NO"
extractDataType (CANCEL _ _ _) = "CANCEL"

这个答案让我想起了一个笑话:一位数学家在雾气弥漫的田野上散步,突然看到一只低飞的气球。气球上的乘客向他喊道:“先生,你能告诉我们我们现在在哪里吗?”数学家回答道:“当然可以。你们现在在一个气球里。” 回答是正确的,但完全没有用处。 - Andreas Abel
这个回答让我想起一个笑话:有一天,一个数学家在一个雾蒙蒙的田野上散步,突然一只低飞的气球出现在他的视线中。一个气球乘客大声喊道:“先生,你能告诉我们我们在哪里吗?”数学家大声回答道:“当然可以。你们在一个气球里。” 没错,但完全没用。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接