"Elm에서는 중첩 레코드 업데이트를 수행할 수 없습니다."

5216 단어 elmwebdevbeginners
적어도 직관적인 방식은 아닙니다. 새로운 개발자가 언어를 시작할 때 겪는 첫 번째 고충 중 하나입니다.

주어진:

type alias Model =
    { person : Person
    }

type alias Person =
    { firstName : String
    , lastName : String
    }


... update 함수를 작성할 때 시도해야 할 자연스러운 현상은 다음과 같습니다.

update msg model =
    case msg of
        UpdatedFirstName firstName ->
            { model | person =
              { model.person |
                  firstName = firstName
              }
            }


컴파일러는 그것을 좋아하지 않을 것입니다. 당신도 마찬가지입니다. 이것은 방법이 아닙니다.

자연스러운 다음 단계는 항상 다음과 같습니다.

update msg model =
    case msg of
        UpdatedFirstName firstName ->
            let
                currentPerson = model.person

                updatedPerson =
                    { currentPerson | firstName = firstName }
            in
            { model | person = updatedPerson }


하지만 우리가 더 좋습니다. 우리는 더 잘할 수 있습니다. 날 따라와


Elm은 정말, 정말 간단한 언어입니다. 언어의 모든 것은 내부적으로 일관된 의미 체계를 따릅니다. 나는 무언가가 내가 예상한 대로 작동하지 않을 때 내 기대가 틀렸다는 것을 의미합니다. 즉, 언어의 정신적 모델이 불완전하거나 잘못되었음을 의미합니다. (주의: "기대하는 대로 작동하는"시스템을 설계한다고 주장하는 사람들 - 어떻게 그런 주장을 할 수 있습니까? 이러한 일이 예상대로 정확히 작동하는 사람들의 하위 집합은 누구입니까? 그들은 최적화하기에 적합한 사람들의 하위 집합입니까? 1 )

몇 주 전에 느릅나무 전구 중 하나가 소켓에 깔끔하게 떨어졌고 나는 느릅나무의 지침 중 하나를 발견했습니다.

기능은 왼쪽으로 이동합니다. 매개변수는 오른쪽으로 이동합니다.



(네, 알아요|> ; 거울이 어떻게 작동하는지 아세요?)

이것은 충분히 명백해 보이지만, 모든 것이 즉시 명백하지는 않은 흥미로운 함의를 갖고 있습니다. a 가 있고 b 로 바꾸고 싶다면 a 왼쪽에 함수를 넣어 b 로 바꾸면 됩니다. 함수를 호출하고 다음과 같이 호출합니다.

aToB : a -> b

aToB valueA


하지만 한 번만 사용해야 하는 경우에는 어떻게 해야 합니까? 왜 그냥 람다를 작성하지 않습니까?

(\a -> b) valueA



하지만 당신은 이미 알고 있었고, 나는 아직 방에 있는 코끼리에게 말을 걸지 않았습니다. 값을 취하고 레코드를 반환하는 람다를 작성할 수 있다는 것도 알고 있었을 것입니다.

왜 나는 이것을 전에 보지 못했습니까?

update msg model =
    case msg of
        UpdatedFirstName firstName ->
            { model |
                person =
                    (\p ->
                        { p | firstName = firstName }
                    ) model.person
            }


"와, 존. 깔끔한 파티 트릭. 하지만 -"



네가 옳아. 이것은 은색 총알이 아닙니다. 때때로, 당신은 당신을 위해 이것을 하는 함수를 작성해야 합니다. 어떤 사람들은 빌더 패턴2을 사용하여 다음과 같이 깔끔한 작업을 할 수 있습니다.

update msg model =
    case msg of
        UpdatedFirstName firstName ->
            { model | person =
                model.person
                    |> withUpdatedFirstName firstName
            }

withUpdatedFirstName : String -> Person -> Person
withUpdatedFirstName firstName =
    (\person -> { person | firstName = firstName } )


그러나 update 함수에서 중첩 레코드를 한 번만 업데이트하면 되므로 빌더 패턴에 항상 도달할 필요는 없습니다.

게다가, 그것은 이 작은 에세이의 원래 내용도 아닙니다.

Elm 초급 또는 중급 개발자로서 "이를 수행하는 더 나은 방법이 있어야 함"을 느낀다면 아마도 있을 것입니다. 찾으러 가서 찾을 때까지 찾는 것을 멈추지 마십시오.

그게 다야. 잘자, 조심해.


업데이트/편집: 지난 밤에 Elm Slack3에 이것을 게시했으며 Jeroen Engels는 친절하게 이 글을 읽고 약간의 정오표를 자세히 설명하고 몇 가지 개선 사항을 제안했습니다. 여기에서 그의 말을 인용하겠습니다.

I think one of the options I end up going for in the end, is to have a separate function to update Person, in a separate Person module where the Person type is opaque. That's I think usually where you get the most benefits and it feels least cumbersome (if you already have the opaque type), and I think it would be valuable to mention it here.



불투명한 유형은 이 게시물의 범위를 벗어납니다4, 그러나Charlie Koster does a great job of explaining them, here, for anyone interested.



DHH를 사랑하거나 싫어하거나, 이 문서는 여전히 관련이 있습니다: https://rubyonrails.org/doctrine - Ctrl+F "surprise" 관련 섹션으로 이동합니다.

https://sporto.github.io/elm-patterns/basic/builder-pattern.html  

http://elmlang.herokuapp.com/  

나는 그것을 설명할 자격이 없다고 느끼기 때문에, 그리고 나의 schtick은 "초보자를 그들 자신으로부터 구하는 것"과 "내 죄를 속죄하는 것"이기 때문입니다. 아직 배울 것이 많습니다.

좋은 웹페이지 즐겨찾기