record - 有没有办法将字段名称传递给 setter 函数?

标签 record elm setter

这里我有几个函数,它们都只在模型记录上设置一个字段。 在更动态的语言中,我只需一个 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/

相关文章:

Elm:您将如何构建和设计您的 UI?

math - 榆树有无穷大的常数吗?

ios - uiviewcontroller alloc 在访问时更改 setter/getter 值?

c# - "Getters should not include large amounts of logic."是真是假?

c# - 为 C# 自动属性赋予初始值的最佳方法是什么?

json - 使用 PowerQuery 从列表中的 JSON 记录中提取逗号分隔值

php - #1062 - 重复条目

exception - Azure数据工厂复制事件错误记录异常处理

electron - 在开发过程中是否可以在 Electron 应用程序中使用 Elm 的调试器?

haskell - 在不设置 -Wunused-top-binds 的情况下,推荐使用模块私有(private)记录类型的方法是什么?