【发布时间】:2019-10-29 22:01:10
【问题描述】:
我正在尝试构建一个允许用户操作递归数据结构的 UI。例如,想象一个可视化模式编辑器或数据库表编辑器,其中有普通的旧类型(字符串和整数)和由这些普通类型(数组、结构)组成的复合类型。在下面的示例中,Struct_ 类似于 JavaScript 对象,其中键是字符串,值是任意类型,包括嵌套的 Array_s 和 Struct_s。
-- underscores appended to prevent confusion about native Elm types. These are custom to my application.
type ValueType
= String_
| Int_
| Float_
| Array_ ValueType
| Struct_ (List (String, ValueType))
type alias Field =
{ id : Int
, label : String
, hint : String
, hidden : Bool
, valueType : ValueType
}
type alias Schema = List Field
现在要为此构建一个 UI,我可以创建一个简单的递归函数:
viewField : Field -> Html Msg
viewField field =
div []
[ input [ type_ "text", value field.label ] []
, viewValueType field.valueType
]
viewValueType : ValueType -> Html Msg
viewValueType valueType =
let
structField : (String, ValueType) -> Html Msg
structField (key, subtype) =
div []
[ input [type_ "text", placeholder "Key", value key, onInput EditStructSubfieldKey] []
, viewValueType subtype
]
options : List(Html Msg)
options = case valueType of
String_ -> -- string ui
Int_ -> -- int ui
Float_ -> -- float ui
Array_ subtype ->
[ label [] [ text "subtype" ]
, viewValueType subtype
]
Struct_ fields ->
[ label [] [ text "subfields" ]
, List.map structField fields
, button [ onClick AddStructSubfield ] [ text "Add subfield" ]
]
in
div [] options
我的问题是在尝试使用这种递归结构来操纵我的状态时出现的。 Msgs 中的什么数据结构可以容纳用户对此结构的编辑、添加新字段、子字段以及编辑它们的属性?如何在我的 update 循环中正确解码?
例如...
type alias Model =
{ fields : List Field }
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
AddStructSubfield _???_ ->
({model | fields = ???}, Cmd.none)
EditStructSubfieldKey _???_ ->
({model | fields = ???}, Cmd.none)
您将向AddStructSubfield 或EditStructSubfieldKey 消息附加什么样的数据(通过onClick 处理程序传递给上面的button)以正确更新您的状态,特别是当Struct_ 是说,嵌套在另一个 Struct_ 中,嵌套在 Array_ 中?例如,EditStructSubfieldKey 将只包含用户输入的新字符串,但没有足够的信息来处理深层嵌套的项目。
【问题讨论】:
标签: recursion functional-programming elm