榆树:更新子类型的值

Gui*_*bel 1 elm

我有这种类型

type alias Cat =
 { head : Head
 }

type alias Head =
  { eyes : Int
  , nose : Int
  , mouth : Mouth
  }

type alias Mouth =
  { tongue : Int
  , prey : Prey
  }

type alias Prey =
  { left : Int
  , right : Int 
  }
Run Code Online (Sandbox Code Playgroud)

插入值

cat : Cat
cat = 
  { head = 
    { eyes = 2
    , nose = 1
    , mouth = 
      { tongue = 1
      , prey = 
        { left = 1
        , right = 1
        }
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

我通常这样做是为了改变猎物的右侧

let  
  newCat = 
    (Cat 
      (Head oldValue.eyes oldValue.nose 
        (Mouth 
          (Prey oldValue.left 1)
        )
      )
    )
in
 ({model | cat = newCat }, Cmd.none)
Run Code Online (Sandbox Code Playgroud)

我讨厌这样做,但我无法弄清楚如何以正确的方式做到这一点.当我尝试做正确的时候,我无法返回'类型猫'.

如何以正确的方式改变正确的猎物?

Emm*_*osa 5

你已经以正确的方式做到了.

当你处理嵌套记录时,你必须建立它们,就像你已经在做的那样.

现在,您可以做的是抽象newCat并将其转换为类型函数Int -> Cat -> Cat.然后,你就能做到({model | cat = updateRightPrey 1 model.cat }, Cmd.none)

但老实说,您可能想重新考虑您的数据模型.确实Head,Mouth和Prey实际提供什么价值?如果你像这样展平你的模型,你会放松什么(以及你必须获得什么):

type alias Cat = 
  { eyes : Eyes
  , nose : Nose
  , tongue : Tongue
  , left : Prey
  , right : Prey 
  }

type alias Eyes = Int
type alias Nose = Int
type alias Tongue = Int
type alias Prey = Int
Run Code Online (Sandbox Code Playgroud)

即使您将所有Int类型别名更改为类型...

type Eyes = Eyes Int
Run Code Online (Sandbox Code Playgroud)

...它比处理嵌套记录要简单得多:

let
    cat = model.cat
in
({model | cat = { cat | right = 1 }, Cmd.none)
Run Code Online (Sandbox Code Playgroud)

要么...

let
    cat = model.cat
in
({model | cat = { cat | right = Prey 1 }, Cmd.none)
Run Code Online (Sandbox Code Playgroud)