Elm:自定义类型的访问值

Elm: Access value of custom type

我在 Elm 中有一个自定义类型来处理错误分支。基本上,我有一个输入,它给出 Strings,我需要将其转换为 Ints。

type Seconds
    = Error Int
    | Valid Int

type alias Model =
    { timeBetweenExercises : Seconds
    , roundsSequenceOne : Seconds
    , roundsSequenceTwo : Seconds
    , roundsSequenceThree : Seconds
    , repititionsPerExercise : Seconds
    , secondsPerExercise : Seconds
    , totalTrainingDuration : Seconds
    }


init : Model
init =
    { timeBetweenExercises = Valid 3
    , roundsSequenceOne = Valid 3
    , roundsSequenceTwo = Valid 3
    , roundsSequenceThree = Valid 3
    , repetitionsPerExercise = Valid 6
    , secondsPerExercise = Valid 6
    , totalTrainingDuration = Valid 6
    }

我从 Evan's "Life of a file" talk 那里得到了自定义类型的想法。我想在出现错误时记住数字(例如,用户输入的是字符串而不是数字)。这是我的更新功能的尝试:

update : Msg -> Model -> Model
update msg model =
    case msg of
        TimeBetweenExercisesChanged newTime ->
            case String.toInt newTime of
                Nothing ->
                    { model | timeBetweenExercises = Error model.timeBetweenExercises }

                Just time ->
                    { model | timeBetweenExercises = Valid time }

我的问题是,编译器对我大吼大叫,因为 model.timeBetweenExercisesSeconds 类型。有没有办法只获取自定义类型的Int值?

在我看来模型是错误的,原因有二:

  1. 如果您有一个在所有情况下都通用的值,通常将其移出和移上一个级别会更方便。

  2. 您的更新函数表明 Error 状态实际上并没有描述它所持有的值,因为您只是在 newTime 无效时丢弃并使用旧的Error 案例的时间到了。

基于此,我建议改用以下模型:

type alias TimeInput =
    { seconds: Int
    , state: TimeInputState
    }

type TimeInputState = Error | Valid

type alias Model =
    { timeBetweenExercises : TimeInput
      ...
    }

并将您的更新功能更改为:

update : Msg -> Model -> Model
update msg model =
    case msg of
        TimeBetweenExercisesChanged newTime ->
            case String.toInt newTime of
                Nothing ->
                    { model
                        | timeBetweenExercises = 
                            { seconds = model.timeBetweenExercises.seconds
                            , state = Error
                            }
                    }

                Just time ->
                    { model
                        | timeBetweenExercises = 
                            { seconds = time
                            , state = Valid
                            }
                    }

否则,无论哪种情况,您总是可以创建一个函数来提取 Int

getSeconds : Seconds -> Int
getSeconds time =
    case time of
        Error seconds -> seconds
        Valid seconds -> seconds