如何在PureScript中组合记录类型的行? (PureScript 0.12.0中是否有Union类型类的替代方法?)

问题描述 投票:2回答:1

问题:我有许多常见字段的不同记录类型。我如何“包含”记录类型定义中的公共字段?

例:

newtype RecordType1 = RecordType1 { a :: Int, b :: Int, y :: String }
newtype RecordType2 = RecordType2 { a :: Int, b :: Int, z :: Boolean } 

如何在PureScript中编写等效的?

newtype RecordType1 = RecordType1 { CommonFields, y :: String }
newtype RecordType2 = RecordType2 { CommonFields, z :: Boolean }

Union中提到的类型类An Overview of the PureScript Type System可能是我想要的...但它似乎是自PureScript 0.12.0以来。

有什么建议?有什么我想念的吗?

谢谢!

union rows records purescript
1个回答
9
投票

PureScript具有用于组合行的特殊语法:

type Common = ( a :: Int, b :: Int )
type Record1 = { y :: String | Common }
type Record2 = { z :: Boolean | Common }
newtype RecordType3 = RecordType3 { w :: Number | Common }

请注意,Common的定义使用括号,而不是花括号。那是因为Common是一排,而不是记录。你可以创建一个记录:

type CommonRec = Record Common 
-- equivalent to:  CommonRec = { a :: Int, b :: Int }

实际上,花括号符号只是将Record应用于行的语法糖。一个表达{ xyz }去了Record ( xyz ) desugared。

您也可以使用“管道”语法来扩展行:

type CommonPlusFoo = ( foo :: Bar | Common )
type RecWithFoo = { x :: Int | CommonPlusFoo }

您还可以通过提供Common作为类型参数来使记录类型具有多态性:

type Record1Poly r = { y :: String | r }
type Record1 = Record1Poly Common

这对于编写使用部分记录的函数非常方便,例如:

updateName :: forall r. { name :: String | r } -> { name :: String | r }
updateName x = x { name = "Mr. " <> x.name }

jones = { name: "Jones", occupation: "Plumber" }
mrJones = updateName jones  -- mrJones = { name: "Mr. Jones", occupation: "Plumber" }

在此示例中,该函数可以与任何具有name字段的记录一起使用,无论它可能具有什么。


最后,要表示一个空行,请使用空的parens:

type Record1Poly r = { y :: String | r }
type Record1 = Record1Poly Common
type OnlyY = Record1Poly ()

在一个稍微不相关的主题上,请注意PureScript中的记录与Haskell中的记录不同。例如,上面的Record1Record2是真正的PureScript ad-hoc可扩展记录(Haskell没有的东西),但RecordType3是一个新类型,它有一个构造函数,其参数是一个记录。

一个重要的区别是,与Haskell不同,这不起作用:

 x = RecordType3 { w: 42.0, a: 1, b: 2 }
 y = w x

表达式w x(甚至表达式x.w)不能编译,因为RecordType3本身不是一个记录,它是一个包装记录的新类型。为了从中获取w,您需要首先匹配构造函数:

 (RecordType3 k) = x
 y = k.w

或者将其作为访问者函数包装:

 unRecordType3 (RecordType3 k) = k
 y = (unRecordType3 x).w

实际上,如果您正在接近具有Haskell思维模式的记录,这真的很不方便。相反,你想要在PureScript中做什么更喜欢“裸”记录(如上面的例子中的Record1Record2),并且只在你需要的时候将它们包装在newtype中。

© www.soinside.com 2019 - 2024. All rights reserved.