You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让PureScript中不同的record type类型不相等?

在PureScript中实现标称化的Record类型以保证类型安全

PureScript中使用type定义的Record类型本质是类型别名,仅为底层结构类型赋予新名称,因此结构相同的别名类型会被编译器视为同一类型,自然可以直接比较。要实现类似Haskell中data Foo = Foo {a :: Int}的标称类型(Nominal Type)效果,让结构相同的不同类型无法直接比较,你可以使用newtype来包装Record。

解决方案代码示例

module Main where

import Prelude

import Effect (Effect)
import Effect.Console (log)
import Data.Eq (Eq)

-- 用newtype包装Record,创建独立的标称类型
newtype Foo = Foo { a :: Int }
-- 派生Eq实例,让Foo类型支持相等比较
derive newtype instance eqFoo :: Eq Foo

newtype Bar = Bar { a :: Int }
derive newtype instance eqBar :: Eq Bar

foo :: Foo
foo = Foo { a: 1 }

bar :: Bar
bar = Bar { a: 1 }

main :: Effect Unit
main = do
  -- 编译报错:无法比较Foo和Bar类型的值
  log $ show $ foo == bar

效果说明

上述代码中,Foo和Bar是完全独立的标称类型,即使它们内部的Record结构完全一致,编译器也会阻止跨类型的相等比较,符合你预期的类型安全要求。

访问内部Record字段

如果需要访问包装后的Record字段,可以通过模式匹配或Data.Newtype模块提供的工具:

import Data.Newtype (class Newtype, unwrap)

-- 实现Newtype实例,方便通用地解包
derive newtype instance newtypeFoo :: Newtype Foo _
derive newtype instance newtypeBar :: Newtype Bar _

-- 解包获取内部Record
fooRecord = unwrap foo
-- 直接访问字段
fooA = case foo of Foo r -> r.a

与Haskell实现的对比

Haskell中data Foo = Foo {a :: Int}的方式会生成带Record语法的代数数据类型,而PureScript的newtype是更轻量的选择——它在运行时不会带来额外的性能开销,仅在编译时提供类型区分,是实现标称化Record的最优方案。

内容的提问来源于stack exchange,提问作者Hi-Angel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:47:33