【问题标题】:Accessing members of a custom data type in Haskell在 Haskell 中访问自定义数据类型的成员
【发布时间】:2020-06-23 07:44:14
【问题描述】:

假设我在 Haskell 中有以下自定义数据类型和函数:

data Person = Person { first_name :: String, 
                       last_name :: String,
                       age :: Int 
                     } deriving (Eq, Ord, Show)

如果我想创建一个函数print_age 来打印一个人的年龄,例如:print_age (Person "John" "Smith" 21),我将如何编写print_age 来访问年龄参数?我是一个面向对象的人,所以我在这里没有我的元素。我基本上是在寻找 Person.age 的等价物。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    函数应用是前缀,所以age person 将对应于OOP 语言中常见的person.age()print_age 函数可以通过函数组合定义无点

    print_age = print . age
    

    或点满

    print_age person = print (age person)
    

    【讨论】:

      【解决方案2】:

      这称为记录语法,LYAH has a good section on it

      当用记录定义数据类型时,Haskell 会自动定义与记录同名的函数作为访问器,所以在这种情况下age 是年龄字段的访问器(它的类型为Person -> Int), first_namelast_name 也是如此。

      这些是普通的 Haskell 函数,因此被称为 age personfirst_name person

      【讨论】:

      • 在 Frege(用于 JVM 的 Haskell)中,一条记录引入了一个命名空间,因此您可以编写 Person.age person。另一方面,Frege 允许编写 person.age,就像在 OO 中一样。
      • 作为一个完整的(!)新手,我发现记录产生的命名空间混乱是丑陋和令人沮丧的。 Frege 语法很有吸引力,iiuc 避免了这个问题。
      • 啊,我知道我并不孤单:ghc.haskell.org/trac/ghc/wiki/Records/NameSpacing
      【解决方案3】:

      除了其他答案中提到的age函数外,有时使用模式匹配也很方便。

      print_age Person { age = a } = {- the a variable contains the person's age -}
      

      有一个非常无害的扩展,可以让你跳过命名位:

      {-# LANGUAGE NamedFieldPuns #-}
      print_age Person { age } = {- the age variable contains the person's age -}
      

      ...还有一个,不同社区成员以不同程度的不信任看待,这使您甚至可以跳过说出要纳入范围的字段:

      {-# LANGUAGE RecordWildCards #-}
      print_age Person { .. } = {- first_name, last_name, and age are all defined -}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-05
        • 1970-01-01
        • 1970-01-01
        • 2011-12-20
        • 1970-01-01
        • 2022-01-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多