2015-07-03 60 views
6

我觉得类型签名看起来像f :: a -> [Int] 输入数据看起来像data NamedPoint = NamedPoint String Int Int是否有一个通用函数需要一个数据结构并返回其中的所有int值?

data Person = Name Int Int Int 

,并在REPL使用它是这样的:

>> let namedPoint = NamedPoint "hey" 1 2 
>> let tommy = Person "Tommy" 1 2 3 
>> f namedPoint 
>> [1,2] 
>> f Tommy 
>> [1,2,3] 

我认为这将是有用另一种方法是记录你什么时候懒得为具有很多参数的数据编写getter。

+3

如果输入的数据将是''NamedPoint ''为什么函数不能输入为''f :: NamedPoint - > [Int]''? – zegkljan

+0

在这种情况下,它可以。但我认为这种行为可能对提取泛化类型有用。生病编辑我的问题更具体。 – user514156

+0

对于此任务,uniplate是最简单的选择。你的f就是universeBi函数。 – augustss

回答

10

Data类是有能力的。我发现使用lens包的template遍历最简单的方法。这基本上可以让你设置或获取任何与Data实例。在ghci的:

> import Data.Data 
> import Control.Lens 
> import Data.Data.Lens 

> -- Data is a derivable class 
> :set -XDeriveDataTypeable 
> data NamedPoint = NamedPoint String Int Int deriving (Data, Show) 
> data Person = Name String Int Int Int deriving (Data, Show) 
> let namedPoint = NamedPoint "hey" 1 2 
> let tommy = Name "Tommy" 1 2 3 

> let ints = toListOf template :: Data a => a -> [Int] 
> ints namedPoint 
[1,2] 
> ints tommy 
[1,2,3] 

因为template是穿越,你也可以映射在值(但你可能需要指定类型):

> namedPoint & template *~ (10 :: Int) 
NamedPoint "hey" 10 20 
> import Data.Char 
> tommy & template %~ toUpper 
Name "TOMMY" 1 2 3 
9

这对于您描述的类型签名的函数是不可能的。想想f :: a -> [Int]的含义:f应该是一个函数,其值为任意可能的类型并返回Int s的列表。应该如何定义这样的功能?唯一可能的定义是,它忽略了参数,并返回一个恒定值,像

f :: a -> [Int] 
f _ = [0] 

如果你知道你a将是,为什么不使用这种类型的?就像这样:

f :: NamedPoint -> [Int] 
f (NamedPoint _ a b) = [a, b] 

如果你想要一些“一般”功能从一个数据类型返回所有​​Int S,其中一个方案是定义一个类型类

class IntContainer a where 
    f :: a -> [Int] 

,然后定义实例为你的数据类型有兴趣

instance IntContainer NamedPoint where 
    f (NamedPoint _ a b) = [a, b] 
+0

我认为这将适用于我的用例谢谢! – user514156

+1

“这是不可能的”有点夸大其词 - 这并不是微不足道的,严格来说,可能与所提到的确切签名('a :: [Int]')不同,但完全可以实现OP要求的内容。 –

+0

@ErikAllik感谢您的注意,我不知道。我编辑答案更准确。 – zegkljan

相关问题