【问题标题】:Dynamic records in Elm 0.18Elm 0.18 中的动态记录
【发布时间】:2017-09-21 19:08:50
【问题描述】:

我的 Elm 应用程序中的模型有一些嵌套记录。我目前正在使用正常的不可变函数设置它们。

Types.elm

type alias Model =
    { settings : Settings
    ...
    }

type alias Settings = 
    { username : String
    , password : String
    ...
    }

App.elm

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        SetUsername username ->
            ( model |> setUserName username, Cmd.none )

        SetPassword password ->
            ( model |> setPassword password, Cmd.none )

Setters.elm

setUserName : String -> Model -> Model
setUserName username model =
    let
        oldUserSettings =
            model.userSettings

        newUserSettings =
            { oldUserSettings | username = username }
    in
        { model | userSettings = newUserSettings }


setPassword : String -> Model -> Model
setPassword password model =
    let
        oldUserSettings =
            model.userSettings

        newUserSettings =
            { oldUserSettings | password = password }
    in
        { model | userSettings = newUserSettings }

我想概括一下 Setter,以便我可以动态设置它们。像这样的:

setUserSettings : String -> String -> Model
setUserSettings field variable model =
    let
        oldUserSettings =
            model.userSettings

        newUserSettings =
            { oldUserSettings | field = variable }
    in
        { model | userSettings = newUserSettings }

setUserName : String -> Model -> Model
setUserName value model =
  setUserSettings username value

setPassword : String -> Model -> Model
setPassword value model =
  setUserSettings password value

最像榆树的方法是什么?

【问题讨论】:

标签: immutability elm dynamic-variables


【解决方案1】:

如前所述,没有用于设置记录字段的内置语法。

由于这个限制,我认为您当前的代码很好。但是如果Settings中出现了更多的字段,那么将访问嵌套字段的逻辑提取到单独的函数中可能会很有用:

setUserName : String -> Model -> Model
setUserName username model =
    setUserSettings model (\r -> { r | username = username })


setPassword : String -> Model -> Model
setPassword password model =
    setUserSettings model (\r -> { r | password = password })


setUserSettings : Model -> (Settings -> Settings) -> Model
setUserSettings model updateSettings =
    let
        oldUserSettings =
            model.userSettings

        newUserSettings =
            updateSettings oldUserSettings
    in
        { model | userSettings = newUserSettings }

如果出现更深的嵌套,您可能会发现focus library 很有用。 Here 是其用法的一个示例。

在您当前的情况下,库会将您的代码修改为:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    let
        userSettings =
            create .userSettings (\f r -> { r | userSettings = f r.userSettings })

        username =
            create .username (\f r -> { r | username = f r.username })

        password =
            create .password (\f r -> { r | password = f r.password })

    in
        case msg of
            SetUsername value ->
                ( set (userSettings => username) value model, Cmd.none )

            SetPassword value ->
                ( set (userSettings => password) value model, Cmd.none )

但这两种解决方案都不是完美的,因为您需要为每个字段定义一个自定义设置器。

【讨论】:

  • 我明白为什么存在这个限制了;像这样对动态变量进行类型检查要困难得多。 Haskell 是否施加了同样的限制?
  • 是的,您提供的那段代码(关于动态访问记录中的字段)很难进行类型检查
猜你喜欢
  • 2018-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多