2017-02-08 5 views
8

레코드의 중첩 된 값을 업데이트하는 간결한 방법 Elm (0.18) 레코드의 중첩 된 값을 업데이트하는 간결한 방법을 찾고 있습니다.Elm (0.18)

다음 예 감안할 때 :

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

나는 "스티브"다음 식을 사용하는 person.name를 업데이트 할 수 있습니다 그러나

{ person | name = "Steve" } 

를, 내가 중첩을 업데이트하는 방법을 찾고 있어요 값. 예를 들어, 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 예제를 당분간 사용하고 싶을 수 있습니다.

여기 Elm에서 설정 값을 더 쉽게 만들 수있는 older discussion on the topic가 있지만 얼마 동안 활성화되지 않았습니다.

당신은 다음과 같이하고, String ( { name: String, address: { city: String, country: String }에 대한 type alias 인)을 Person를 수신하고 업데이트 된 기록을 반환하는 함수를 만들 수 있습니다
+0

자세한 답변을 보내 주셔서 감사합니다. 엘름 (Elm)의 설탕 설탕을 이런 종류의 구조물에 사용하기를 바랬습니다. – jakubr

+2

오늘 중첩 된 레코드 업데이트를 수행하기 위해 내 자신의 구문 설탕을 만드는 방법에 대한 게시물을 게시했습니다. https://medium.com/elm-shorts/updating-nested-records-in-elm-15d162e80480?source=collection_home---5------0-0-- – wintvelt

+0

That 's 예쁜 매끄러운, @wintvelt! 나는 flip/piping 방법의 가독성과 간결함을 좋아합니다. –

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