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

使用purescript-argonaut-codecs处理含枚举与可变子Schema的复杂JSON

在PureScript中处理带可变子Schema的复杂JSON结构问题

我有一个包含可变子JSON的复杂JSON结构,每个子JSON都有独立Schema,结构示例如下:

{
  "node_level": "unit",
  "name": "unit 1",
  "description": "the first unit",
  "theme_image_path": "hello.png",
  "children": [
    {
      "node_level": "chapter",
      "name": "chapter 1",
      "theme_image_path": "dog.png",
      "children": [
        {
          "node_level": "lesson",
          "lesson_type": "reading",
          "children": [
            {
              "node_level": "activity",
              "activity_type": "vocabulary",
              "elements": { /* 此处结构随activity_type系统变化 */ }
            }
          ]
        }
      ]
    }
  ]
}

注意:activity层级对应多种不同的对象Schema——每种activity_type对应专属Schema,activity_type和elements字段会随之变化。

我当前基于purescript-argonaut-codecs库的实现无法正常运行(报错见下文),也未达成部分目标,具体实现代码如下:

import Data.Argonaut.Encode (encodeJson)

-- 当前代码报错
contentToJson :: Content -> Json
contentToJson = encodeJson

type UnitNode = 
  { node_level :: String -- 希望强制该值为"unit"(见问题3)
  , name :: String
  , description :: String
  , theme_image_path :: String
  , children :: Array ChapterNode
  }

type ChapterNode = 
  { node_level :: String -- 希望强制该值为"chapter"(见问题3)
  , name :: String
  , theme_image_path :: String
  , children :: Array LessonNode
  }

type LessonNode = 
  { node_level :: String -- 希望强制该值为"lesson"(见问题3)
  , lesson_type :: String -- 希望实现枚举类形式(见问题1)
  , children :: Array ActivityNode
  }

type ActivityNode = 
  { node_level :: String -- 希望强制该值为"activity"(见问题3)
  , layout :: String -- 希望实现枚举类形式(见问题1)
  , elements :: VocabFlashcard -- 此处应支持多种类型(见问题2)
  }

type VocabFlashcard =
  { audio :: String
  , image :: String
  , vocabText :: String
  , translation :: String
  }

我在PureScript中遇到以下三个难题,这些在TypeScript中均可实现,若无法解决将考虑转回TypeScript:

1. 枚举类字段的类型约束与编解码器问题

部分字段(node_level、lesson_type、activity_type)只能取特定闭合字符串子集,比如node_level仅能为"unit"、"chapter"、"lesson"或"activity"。在TypeScript中我会用type NodeLevel = "unit" | "chapter" | "activity" | "lesson"实现,但在PureScript中尝试两种方法均遇问题:

  • 方法①:使用newtype:无编解码器时可正常工作,但编解码器库报错:
No type class instance was found for

    Data.Argonaut.Encode.Class.EncodeJson LessonType


while solving type class constraint

  Data.Argonaut.Encode.Class.GEncodeJson ( children :: Array
                                                         { elements :: { audio :: String
                                                                       , image :: String
                                                                       , translation :: String
                                                                       , vocabText :: String
                                                                       }
                                                         , layout :: String
                                                         , node_level :: String
                                                         }
                                         , lesson_type :: LessonType
                                         , node_level :: String
                                         )
                                         (Cons @Type "lesson_type" LessonType (Cons @Type "node_level" String (Nil @Type)))

while checking that type forall (@a :: Type). EncodeJson a => a -> Json
  is at least as general as type Array
                                   { children :: Array ...
                                   , description :: String
                                   , name :: String
                                   , node_level :: String
                                   , theme_image_path :: String
                                   }
                                 -> Json
while checking that expression encodeJson
  has type Array
             { children :: Array ...
             , description :: String
             , name :: String
             , node_level :: String
             , theme_image_path :: String
             }
           -> Json
in value declaration contentToJson
  • 方法②:使用枚举类data类型:虽可行但代码过于冗长,且同样遇到编解码器报错:No type class instance was found for Data.Argonaut.Encode.Class.EncodeJson NodeLevel ...

2. 可变子Schema的联合类型实现问题

在TypeScript中我会用联合类型实现(示例代码如下),确保Activity数组符合特定Schema。但PureScript似乎不支持用|运算符定义多类型联合,是否应使用data类型?若如此又会遇到上述编解码器问题。

type Lesson = {
  node_level: NodeLevel;
  children: Activity[];
  lesson_type: LessonType;
}

type ActivityName =
  "vocab"
  | "grammar"
  | (... etc)

type Activity =
  Vocabulary
  | Grammar
  | (... etc)

type Vocabulary = {
  node_level: NodeLevel,
  activity_type: ActivityName,
  elements: {
    audio: string,
    image: string,
    vocabText: string,
    translation: string
  },
}

-- 其他Activity类型定义...

3. 强制固定字段值的类型约束问题

理想情况下,JSON中node_level字段的值需根据层级子Schema强制设定,比如Vocabulary的node_level需固定为"activity"。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:54:54