这里我有几个函数,它们都只在模型记录上设置一个字段。 在更动态的语言中,我只需一个 setter 函数,并将字段名称(作为字符串)和我想要在模型对象上设置的值传递给它。
有没有办法在Elm中传递字段名称? Elm 做这样的事情的方式是什么?
type alias Patient =
{ id : String
, name : String
, dateOfBirth : String
, sex : String
... other fields
}
setPatientName : Patient -> String -> Patient
setPatientName patient value =
{ patient | name = value }
setPatientDateOfBirth : Patient -> String -> Patient
setPatientDateOfBirth patient value =
{ patient | dateOfBirth = value }
setPatientSex : Patient -> String -> Patient
setPatientSex patient value =
{ patient | sex = value }
... many others
-- idx is the index of the patient in the model (which is an array of patients)
-- UpdateCell is a variant of my Msg type, like this: UpdateCell Int (Patient -> String -> Patient) String
onInputHandler : Int -> (Patient -> String -> Patient) -> String -> Msg
onInputHandler idx setter inputText =
UpdateCell idx setter inputText
-- idx is the index of the patient in the model (which is an array of patients)
createTableRow : Int -> Patient -> Html Msg
createTableRow idx patient =
...
, input [ type_ "text", onInput (onInputHandler idx setPatientName), value patient.name ] []
, input [ type_ "text", onInput (onInputHandler idx setPatientDateOfBirth), value patient.dateOfBirth ] []
...
我目前正在使用这些函数作为输入元素的事件处理程序。所以我需要一个可用于处理输入事件的函数。理想情况下,我只定义一个函数,并将该函数用于所有输入元素,并将其传递给我想要在患者记录上更新的字段。
最佳答案
简短的回答是“不”。但这看起来有点像an XY problem 。目前尚不清楚您想要实现什么好处,因为此类函数的完整应用将比等效的记录更新表达式更长:
setField "name" patient value
-- vs
{ patient | name = value }
作为部分应用函数,仅比具有缩短参数名称的等效匿名函数稍短:
setField "name"
-- vs
\r x -> { r | name = x }
尽管后者对于所有符号来说噪音明显更大。
还有一个用于获取记录字段的简写函数:
.name
-- vs
\r -> r.name
因此,也有一些为 setter 函数使用专用语法的先例,但不幸的是没有。可能是因为它会使语言,特别是语法变得复杂,但好处相对较小。因此,我很好奇您实际上想要实现什么目标。
问题更新后编辑:
将函数放入 Msg
中是一个非常糟糕的主意,因为它违背了 Elm 架构。它使状态转换变得不透明,并且不能很好地与调试器配合使用。当出现问题时,您仍然可以看到之前和之后的状态,但您将无法理解发生了什么以及为什么发生,因为该信息被编码在不透明的函数,可能不是它应该的函数。
你也会很难分解你的逻辑。如果您只需要在某个字段更新时发生某些事情,则可能必须将逻辑放入 View 中,或者通过将该字段的逻辑放入 update
中(而其余部分则放在该字段中)来特殊情况例如,查看
。无论哪种方式,您都会走向困惑的代码库。
您通常应该使用描述发生了什么而不是要做什么的消息名称,因为这往往会导致命令式思维。例如,您可以将其称为 InputChanged
,而不是 UpdateCell
。然后,您应该拥有该字段的标识符,而不是该函数。理想情况下是自定义类型,例如 InputChanged Name
,但即使是字符串也可以使用,尽管更容易错过拼写错误。
因此,您只需区分大小写匹配消息并在 update
函数中设置字段即可,而不是为每个字段设置设置函数:
InputChanged Name value ->
{ patient | name = value }
-- vs
setPatientName : Patient -> String -> Patient
setPatientName patient value =
{ patient | name = value }
然后,例如,如果您需要在名称更改时清除性别(因为原因......),您可以简单地执行以下操作:
InputChanged Name value ->
{ patient | name = value, sex = "" }
Elm 架构很好,因为它使更改变得简单且安全,而不是因为它简洁且没有样板。好的 Elm 代码通常有大量的复制粘贴,但这并不总是坏事。
关于record - 有没有办法将字段名称传递给 setter 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59005617/