是否有一个通用函数采用数据结构和 returns 其中的所有整数?
Is there a generic function that takes a data structure and returns all ints in it?
我认为类型签名看起来像 f :: a -> [Int]
输入数据看起来像 data NamedPoint = NamedPoint String 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 时,这可以作为记录的替代方法。
这对于您描述的类型签名的函数是不可能的。想一想 f :: a -> [Int]
的意思:f
应该是一个函数,它取值 any 可能的类型和 returns Int
秒。这样的函数应该如何定义?唯一可能的定义是它忽略参数和 returns 一个常量值,比如
f :: a -> [Int]
f _ = [0]
如果您知道 a
会是什么,为什么不直接使用该类型呢?像这样:
f :: NamedPoint -> [Int]
f (NamedPoint _ a b) = [a, b]
如果你想要一些 "general" 函数从数据类型返回所有 Int
s,一个选择是定义一个类型类
class IntContainer a where
f :: a -> [Int]
然后为您感兴趣的数据类型定义实例
instance IntContainer NamedPoint where
f (NamedPoint _ a b) = [a, b]
Data
class is capable of this. I've found the easiest way to work with it is with the template
traversal from the lens
包。这实质上允许您使用 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
是遍历,所以也可以map over values(但可能需要指定类型):
> namedPoint & template *~ (10 :: Int)
NamedPoint "hey" 10 20
> import Data.Char
> tommy & template %~ toUpper
Name "TOMMY" 1 2 3
我认为类型签名看起来像 f :: a -> [Int]
输入数据看起来像 data NamedPoint = NamedPoint String 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 时,这可以作为记录的替代方法。
这对于您描述的类型签名的函数是不可能的。想一想 f :: a -> [Int]
的意思:f
应该是一个函数,它取值 any 可能的类型和 returns Int
秒。这样的函数应该如何定义?唯一可能的定义是它忽略参数和 returns 一个常量值,比如
f :: a -> [Int]
f _ = [0]
如果您知道 a
会是什么,为什么不直接使用该类型呢?像这样:
f :: NamedPoint -> [Int]
f (NamedPoint _ a b) = [a, b]
如果你想要一些 "general" 函数从数据类型返回所有 Int
s,一个选择是定义一个类型类
class IntContainer a where
f :: a -> [Int]
然后为您感兴趣的数据类型定义实例
instance IntContainer NamedPoint where
f (NamedPoint _ a b) = [a, b]
Data
class is capable of this. I've found the easiest way to work with it is with the template
traversal from the lens
包。这实质上允许您使用 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
是遍历,所以也可以map over values(但可能需要指定类型):
> namedPoint & template *~ (10 :: Int)
NamedPoint "hey" 10 20
> import Data.Char
> tommy & template %~ toUpper
Name "TOMMY" 1 2 3