2017-02-08 4 views
8

Elm(0.18)のレコード内のネストされた値を簡潔に更新する方法を探しています。Elm(0.18)のレコード内でネストされた値を更新する簡単な方法

{ person | name = "Steve" } 

は、しかし、私はネストされたを更新する方法を探しています:私は次の式を使用して、「スティーブ」にperson.nameを更新することができ

person = { name = "Steven", address = { country = "Spain", city = "Barcelona" } } 

は、次の例を考えます値。たとえば、person.address.cityを「Madrid」に更新したいとします。私は、次のことを試してみました:

{ person | address.city = "Madrid" } 
{ person | address = { address | city = "Madrid" } } 
{ person | address = { person.address | city = "Madrid" } } 

コンパイラは、これらすべてのバリエーションを拒否します。私が見最短有効なオプションは次のとおりです。

let personAddress = person.address in { person | address = { personAddress | city = "Madrid" } } 

これは単に、ネストされた値を更新するために、少しあまりにも多くのコードのようです、それを達成するためのより良い/短い方法がある場合は、あなたが知っていますか?

+0

使用ニレ、単眼鏡https://github.com/toastal/toast.al-blog/blob/master/posts/code/2017-01-13-playing-with-prisms-for-the- not -so-isomorphic.md – rofrol

答えて

8

let/in構文の最後の例は、追加のパッケージに頼らずにElm 0.18と同じくらい簡潔です。

言われているように、関数型言語では、ネストされたレコードを更新するのにレンズの概念が役立つことがよくあります。 arturopala/elm-monocleにElmパッケージがあり、ネストされたレコード値をより簡潔に取得して設定するためのレンズを構築して実行する機能を提供します。

personWithUpdatedCity = personCity.set "Madrid" person 

getCityOfPerson = personCity.get person 

欠点は、あなたがすべてのレンズの配線コードを自分で書かなければならないということです、あなたはこのように簡潔なものをやらせるだろうレンズを構築することができ、そのパッケージを使用して

。 Haskellでは、この配線はコンパイラで行うことができます。エルムでは、その贅沢はありません。

エルムこれをだろう上記のレンズのために必要なコード:あなたが見ることができるように

addressCityLens : Lens Address String 
addressCityLens = 
    Lens .city (\cn a -> { a | city = cn }) 

personAddressLens : Lens Person Address 
personAddressLens = 
    Lens .address (\a p -> { p | address = a }) 

personCity : Lens Person String 
personCity = 
    compose personAddressLens addressCityLens 

、それは退屈だとあなたがネストされた値を設定することを期待するよりもはるかに多くのコード。この退屈な部分のために、あなたのコードが入れ子にされたセットをその場で使用していない限り、当時はlet/inの例に固執することができます。

ここでエルムの設定値を簡単にすることができますが、しばらくアクティブではありません。

あなたはこのように、と String{ name: String, address: { city: String, country: String }ため type aliasである) Personを受信して​​、更新されたレコードを返す関数を作ることができ
+0

詳細な応答ありがとうございます。私はエルムの構文的な砂糖がこの種の構造物のために望んでいました。 – jakubr

+2

今日は、入れ子にされたレコード更新を行うために独自の構文砂糖を作る方法に関する記事を公開しました。 https://medium.com/elm-shorts/updating-nested-records-in-elm-15d162e80480?source=collection_home---5------0---------- – wintvelt

+0

That'sかなりスリック、@wintvelt!私はフリップ/配管法の読みやすさと簡潔さが気に入っています。 –

0

:私は更新aのこの種を行う必要がある場合

updateCityAdress : Person -> String -> Person 
updateCityAddress person newCity = 
    { name: person.name, address = { country: person.address.country, city = newCity } 

> updateCityAddress person "Madrid" 
> { name = "Steven", address = { country = "Spain", city = "Madrid" } } 
5

ロット、私はヘルパーを構築する

updateAddress : (Address -> Address) -> Model -> Model 
updateAddress fn m = 
    {m | address = fn m.address } 

とそれを使用する

updateAddress (\a -> { a | city = Madrid }) model 
関連する問題