CAL中的用户定义记录类型?

时间:2010-01-04 14:24:28

标签: functional-programming

我怀疑的一个简单问题。我有简单的功能定义

makePatientFixture :: [ { name :: String, age :: Int} ];
makePatientFixture = [ { name = "Dave", age = 41}, { name = "Denise", age = 45}, { name = "Cameron", age = 5} ];

我实际上想要定义一个名为

的新类型
Patient = { name :: String, age :: Int } 

这意味着我不必一直重复记录结构({name :: String,age :: Int})而不是我的代码看起来像:

makePatientFixture :: [ Patient ];
makePatientFixture = [ { name = "Dave", age = 41}, { name = "Denise", age = 45}, { name = "Cameron", age = 5} ];

这可能吗?从CAL的角度来看是否有意义(可能没有)?

1 个答案:

答案 0 :(得分:0)

CAL不支持别名(Haskell使用'type'关键字),所以你不能只做:

type Patient = {name::String, age::Int}

但是,您可以创建包含记录的新数据类型:

data Patient=
    public Patient
        details :: {name::String, age::Int}
    ;

...但是,这可能不是你需要的。记录非常方便移动结构化数据并使用结构多态(记录子集的自动投影)。您不需要像这样存储数据。 相反,我建议:

data Patient=
    public Patient
        name :: !String
        age  :: !Int
    ;

类型上的'plings'意味着“不要在这里存储懒惰的thunk”,例如我们真的想要一个字符串和int,即使你将一些复杂的表达式应用于Patient构造函数。您可以安全地省略plings,但在大多数情况下包含它们是一种好习惯。

您现在可以使用各种形式的案例分析从这样的患者值中提取元素。您将在手册中看到所有这些内容,但这里有一个摘要:

公开案例分析,位置匹配:

age p =
    case p of
    Patientname age -> age;  // Spot the maintenance problem here!
    ;

公开案例分析,符号匹配:

nameAndAge p =
    case p of
    Patient{name,age} -> (name,age);  // Now it doesn't matter if the Patient constructor grows new arguments
    ;

懒惰提取器

name p =
    let
        Patient{name} = p;  // name is only extracted (and p partially evaluated) if name is required
    in
        name;

单箱提取器

name p =
    p.Patient.name;  // Syntactic sugar for example 1.  Useful when you are _only_ extracting a single field. 

如果需要,您始终可以根据此数据投影记录。 请记住,如果有多种患者,您还可以为患者数据类型设置多个构造函数。

例如,也许有住院病人和门诊病人。这两者都有一些nhs患者记录,但具有与其治疗相关的特定领域。 我们可以代表以下几行:

data Patient=
    public InPatient
        patientRecords :: !PatientRecord
        careCentreID   :: !Int
        department :: !String
        consultant :: !String
    | publicOutPatient
        patientRecords :: !PatientRecord
        appointments :: ![Appointment]
    ;


nhsRecords p =
    case p of
    (InPatient|OutPatient) {patientRecords} -> patientRecords;
    ;

这也使我们能够看到一个非常强大的CAL功能,它可以进行多个构造函数匹配。在这种情况下,我们匹配InPatient和OutPatient,仅投射patientRecords字段。

这使我们能够编写一个'nhsRecords'提取器功能,即使患者构造器中的细节发生变化,我们也能轻松维护这些功能。
实际上,除非构造者来来去去,或者“patientRecords”字段本身发生了什么,否则这个函数永远不会改变。