在Haskell中实例化列表的最短方法是什么?

时间:2018-03-30 22:06:47

标签: haskell

假设我使用记录语法定义了如下数据类型Person

data Person = Person { name :: String
                     , age  :: Int
                     } deriving (Show)

我使用以下方法实例化Person的列表:

people = [Person {name="Alice",   age=27},
          Person {name="Bob",     age=23},
          Person {name="Mallory", age=26}]

然后我意识到,一次定义列表中的许多元素会很笨重,因为重复了nameage这两个词。因此我将代码缩减为:

people = [(Person "Alice"   27),
          (Person "Bob"     23),
          (Person "Mallory" 26)]

由于Haskell中的列表无论如何都是同质的,我怎样才能避免在列表的每个元素中指定类型Person?例如,按照以下代码(不编译)执行某些操作:

Person people = [("Alice"   27),
                 ("Bob"     23),
                 ("Mallory" 26)]

Link to runnable example

3 个答案:

答案 0 :(得分:7)

Person,作为数据值的构造函数,本身就是一个(二进制)函数。您可以从元组列表中构建此列表:

people = map (uncurry Person) [("Alice", 27), ("Bob", 42)]

或者您可以从名单和年龄列表中构建它:

people = zipWith Person ["Alice", "Bob"] [27, 42]

......或者来自其他许多选择。

答案 1 :(得分:3)

笑话回答:

instance Enum Person where
    toEnum i = Person (show i) i
    fromEnum (Person _ i) = i

personList :: [Person]
personList = [toEnum 0..]

还是一个笑话答案:

{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE OverloadedStrings #-}

import Data.String

instance IsString Person where
        fromString ps =
           let (name,read . drop 1 -> age) = break (==':') ps
           in Person name age

personList :: [Person]
personList = ["Me:30"
             ,"Them:55"
             ]

扭曲的笑话回答:

{-# LANGUAGE FlexibleInstances#-}
{-# LANGUAGE OverloadedStrings #-}

import Data.String

instance IsString (Int -> Person) where
        fromString = Person

data Person = Person { name :: String
                     , age  :: Int
                     } deriving (Show)

($$) :: (Int -> Person) -> Int -> Person
($$) = ($)

persons :: [Person]
persons = ["Me" $$ 30, "Them" $$ 55]

评论答案:

personList = map (uncurry Person) [("Me",30), ("Them", 55)]

错误的答案:

personList = zipWith Person ["Me", "Them"] [30,55]

答案 2 :(得分:1)

在Haskell中,人们往往不需要很多代表大量的文字数据,所以我们可能会高兴的是语言没有针对它们的表示进行优化。以下是一些选项:

people = (
  let p = Person in
  [p "Alice"   27,
   p "Bob"     23,
   p "Mallory" 26]
)

或者使用一些基本的解析

people = (
  let p x = p' (words x)
      p' [name, age] = person name (read age) in
  map p $ lines "Alice 27\nBob 23\n Mallory 26"
)

或者只是按照你喜欢的方式执行show people,默认情况下会使用Haskell语法,所以只需将它放在源文件的底部并忘记它。