这里我有几个函数,都只在模型记录上设置了一个字段。用一种更具动态性的语言,我只有一个设置函数,然后将字段名称(作为字符串)和要在模型对象上设置的值传递给它。
是否可以在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 }
尽管后者is与所有符号相比明显更嘈杂。
还有一个获取记录字段的简写功能:
.name
-- vs
\r -> r.name
因此,对于setter函数也具有专用语法也有一些先例,但不幸的是没有。可能是因为这样做会使语言(尤其是语法)复杂化,而带来的收益却相对较少。因此,我对您正在[[实际上想要完成的事情感到好奇。
问题更新后编辑:
在Msg
中放置函数是一个非常糟糕的主意,因为它与Elm体系结构背道而驰。它使状态转换变得不透明,并且在调试器中无法很好地工作。当出现问题时,您仍然可以看到之前和之后的状态,但是您将很难理解what
发生了什么,以及why发生了什么,因为该信息被编码为一个不透明的函数,可能不是t应该的那个。您也将难以理解您的逻辑。如果仅在某个特定字段更新时才需要执行某些操作,则可能必须将逻辑放在视图中,或者通过在update
中放置逻辑,而在view
中放置其余逻辑来特殊处理该字段,例如例。无论哪种方式,您都在通往混乱的代码库的道路上。您通常应该在消息中使用名称来描述发生的事情,而不是描述要做什么,因为这往往会导致命令式心态。例如,您可以代替UpdateCell
来命名为InputChanged
。然后,应该使用该字段的标识符代替该函数。理想情况下是自定义类型,例如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代码经常有很多复制和粘贴,但这并不总是不好的。