如何在 Elm 的模型中添加嵌套元素
How to add a nested element in a model in Elm
是否有执行以下操作的标准方法?
{ model | country =
{ model.country | state =
{ model.country.state | city =
{ model.country.state.city | people =
model.country.state.city.people ++ [ newPerson ]
}
}
}
}
当然,country
、state
、city
都是嵌套在model
中的记录。我只想在嵌套的 city
记录中添加一个人。
以上实际上不起作用。我在第一次提到 model.country
时收到以下错误:
I am looking for one of the following things:
"'"
"|"
an equals sign '='
more letters in this name
whitespace
我能够让它工作的方法是在每一步简单地调用一个函数:
{ model | country = updateCountry newPerson model.country }
updateCountry person country =
{ country | state = updateState newPerson country.state }
然后 updateState
和 updateCity
也一样...
有 https://github.com/evancz/focus 但请注意小字。您能否使用不同的数据结构来代替,例如
Dict ( String, String, String ) Int
然后
addOne country state city =
Dict.update (country, state, city)
(\v -> case v of
Just v_ -> v_ + 1
Nothing -> 1)
database
如果你想做这样的事情,通常最好让记录结构更扁平。
通常:
- 如果您的操作也是嵌套的,则嵌套记录是可以的:如果您对每个级别都有单独的更新功能。 And/or 如果您只想在自己的级别更新嵌套记录。
- 如果您需要对某些嵌套记录进行根级访问,那么扁平化会更好。
我倾向于将所有内容存储在根级别,并包含 ID 以供参考。对于您的示例,这看起来像这样:
type alias Model =
{ persons : Dict PersonID Person
, cities : Dict CityID City
, states : Dict StateID State
, countries : Dict CountryID Country
}
此结构允许您从根级别完全访问所有实体。
所以添加一个人将是:
{ model
| persons =
model.persons
|> Dict.insert newPersonID newPerson
}
获取一个国家/地区的所有城市现在需要做更多的工作顺便说一句:
citiesInCountry : Model -> CountryID -> Dict CityID City
citiesInCountry model countryID =
let
statesInCountry =
model.states
|> Dict.filter (\id state -> state.countryID == countryID)
in
model.cities
|> Dict.filter (\id city -> Dict.member city.stateID statesInCountry)
所以这取决于您的应用中哪个操作更频繁:
- 如果你有很多像"get all grandchildren"这样的操作,那么嵌套方法可能会更好
- 如果你有很多 "update this grandchild",那么扁平的替代方案可能更适合
从今天(0.18.0
)开始,记录更新语法中不允许使用任意表达式。
换句话说,您不能在更新期间访问记录的字段:
model = { model.topProperty | childProperty = "Hello" }
^^^^^^^^^^^^^^^^^
Syntax error
它是用于 Elm 编译器的 planned feature,但现在,您应该考虑重构您的模型或使用其中一种冗长的解决方法。
就个人而言,我更喜欢 let..in
表达式,但我从不使用深度高于 3 的记录。
let..in
例子
它看起来超级冗长,但这种方法没有什么不好。当 Elm 编译器将支持更好的语法时,您将能够重构它。
以此为起点,开发一套用于不同级别更新的辅助函数。
let
-- Deconstruct on every level.
{ model } = init
{ country } = model
{ state } = country
{ city } = state
{ people } = city
in
{ init
| model =
{ model
| country =
{ country
| state =
{ state
| city =
{ city
| people = "John" :: people
}
}
}
}
}
是否有执行以下操作的标准方法?
{ model | country =
{ model.country | state =
{ model.country.state | city =
{ model.country.state.city | people =
model.country.state.city.people ++ [ newPerson ]
}
}
}
}
当然,country
、state
、city
都是嵌套在model
中的记录。我只想在嵌套的 city
记录中添加一个人。
以上实际上不起作用。我在第一次提到 model.country
时收到以下错误:
I am looking for one of the following things:
"'" "|" an equals sign '=' more letters in this name whitespace
我能够让它工作的方法是在每一步简单地调用一个函数:
{ model | country = updateCountry newPerson model.country }
updateCountry person country =
{ country | state = updateState newPerson country.state }
然后 updateState
和 updateCity
也一样...
有 https://github.com/evancz/focus 但请注意小字。您能否使用不同的数据结构来代替,例如
Dict ( String, String, String ) Int
然后
addOne country state city =
Dict.update (country, state, city)
(\v -> case v of
Just v_ -> v_ + 1
Nothing -> 1)
database
如果你想做这样的事情,通常最好让记录结构更扁平。
通常:
- 如果您的操作也是嵌套的,则嵌套记录是可以的:如果您对每个级别都有单独的更新功能。 And/or 如果您只想在自己的级别更新嵌套记录。
- 如果您需要对某些嵌套记录进行根级访问,那么扁平化会更好。
我倾向于将所有内容存储在根级别,并包含 ID 以供参考。对于您的示例,这看起来像这样:
type alias Model =
{ persons : Dict PersonID Person
, cities : Dict CityID City
, states : Dict StateID State
, countries : Dict CountryID Country
}
此结构允许您从根级别完全访问所有实体。 所以添加一个人将是:
{ model
| persons =
model.persons
|> Dict.insert newPersonID newPerson
}
获取一个国家/地区的所有城市现在需要做更多的工作顺便说一句:
citiesInCountry : Model -> CountryID -> Dict CityID City
citiesInCountry model countryID =
let
statesInCountry =
model.states
|> Dict.filter (\id state -> state.countryID == countryID)
in
model.cities
|> Dict.filter (\id city -> Dict.member city.stateID statesInCountry)
所以这取决于您的应用中哪个操作更频繁:
- 如果你有很多像"get all grandchildren"这样的操作,那么嵌套方法可能会更好
- 如果你有很多 "update this grandchild",那么扁平的替代方案可能更适合
从今天(0.18.0
)开始,记录更新语法中不允许使用任意表达式。
换句话说,您不能在更新期间访问记录的字段:
model = { model.topProperty | childProperty = "Hello" }
^^^^^^^^^^^^^^^^^
Syntax error
它是用于 Elm 编译器的 planned feature,但现在,您应该考虑重构您的模型或使用其中一种冗长的解决方法。
就个人而言,我更喜欢 let..in
表达式,但我从不使用深度高于 3 的记录。
let..in
例子
它看起来超级冗长,但这种方法没有什么不好。当 Elm 编译器将支持更好的语法时,您将能够重构它。
以此为起点,开发一套用于不同级别更新的辅助函数。
let
-- Deconstruct on every level.
{ model } = init
{ country } = model
{ state } = country
{ city } = state
{ people } = city
in
{ init
| model =
{ model
| country =
{ country
| state =
{ state
| city =
{ city
| people = "John" :: people
}
}
}
}
}