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

为何无法在PureScript中对行多态变量进行模式匹配?

问题描述

以下是一段PureScript代码:

type MyOtherProps = (value :: String)
type MyProps = (a :: String)

a
  :: forall props phantom allProps
   . Union MyProps MyOtherProps allProps
  => Union props phantom allProps
  => { | props }
  -> Unit
a {} = unit

b = a { a: "hello", value: "apple" }

当尝试将函数a的模式匹配从{}改为非空形式(比如a {value} = unit)时,会触发类型错误。

背景

我希望让联合记录的任意标签变为可选,这样调用a时无需强制提供a或value标签。我明白如果在函数体中使用这些变量,可能会因为它们不存在而导致类型不健全,但不清楚编译器是如何识别这一点的。我知道这和phantom类型的推断有关,但allProps类型是明确的,实在搞不懂为什么模式匹配会失败。

错误输出

[1/1 TypesDoNotUnify] src\Main.purs:45:3

  45  a {a} = unit
        ^^^

  无法匹配类型
    props0
  与类型
    ( a :: t2
    | t3
    )
  在尝试匹配类型 Record props0
    与类型 Record t1
    时,检查表达式 case $1 of
                                   { a: a } -> unit
    是否具有类型 Unit
  在值声明a中
  其中 props0 是一个刚性类型变量
          绑定于 (第0行第0列 - 第0行第0列)
        t1 是未知类型
        t3 是未知类型
        t2 是未知类型

原因分析与解决方案

核心原因

编译器的类型检查无法保证props类型中一定包含a标签。虽然allProps是MyProps和MyOtherProps的联合,但Union props phantom allProps约束只说明props和phantom的联合等于allProps——这意味着props可能只包含value,甚至是空记录,完全不包含a。当你在模式匹配中提取a时,编译器无法确认这个字段一定存在,因此抛出类型不匹配错误。

解决方案

如果你确实需要在函数中访问某个字段,必须在类型约束中明确要求该字段存在于props中:

方案1:明确约束字段存在

直接通过RowCons约束,强制props包含目标字段:

type MyOtherProps = (value :: String)
type MyProps = (a :: String)

a
  :: forall props phantom allProps rest
   . Union MyProps MyOtherProps allProps
  => Union props phantom allProps
  => RowCons "a" String rest props  -- 明确props包含a字段
  => { | props }
  -> Unit
a {a} = unit

方案2:用Partial约束(不推荐,有安全风险)

如果要保留字段可选性,同时允许访问可能不存在的字段,可以用Partial约束,但这会让代码失去类型安全性——访问不存在的字段会触发运行时错误:

import Partial (Partial)

a
  :: forall props phantom allProps
   . Union MyProps MyOtherProps allProps
  => Union props phantom allProps
  => Partial props  -- 允许访问props中任意可能存在的字段
  => { | props }
  -> Unit
a {a} = unit

可选标签的安全实现思路

如果目标是让函数接受空记录、MyProps、MyOtherProps或两者联合作为参数,同时保证类型安全,可以通过多联合约束实现:

a
  :: forall props
   . Union props () MyProps props  -- 接受空或MyProps
  => Union props () MyOtherProps props  -- 接受空或MyOtherProps
  => Union props () (MyProps & MyOtherProps) props  -- 接受两者联合
  => { | props }
  -> Unit
a _ = unit

-- 合法调用示例
a {}  -- 可行
a {a: "hello"}  -- 可行
a {value: "apple"}  -- 可行
a {a: "hello", value: "apple"}  -- 可行

内容的提问来源于stack exchange,提问作者Jose Quesada

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:00:32