在Elm的绑定中是否容易陷入困境?

Bjö*_*ren 6 lazy-evaluation let elm

我有两个功能A和B,可以同时禁用,启用A,启用B,但不能同时启用.看完" 让不可能的国家变得不可能"后,我想尝试在类型级别上强制执行此操作.

我正在考虑的解决方案的简化版本如下.

module Main exposing (main)

import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)

type Model
  = NoneEnabled
  | AEnabled
  | BEnabled

init : Model
init = NoneEnabled

type Msg
  = EnableA
  | DisableA
  | EnableB
  | DisableB

view : Model -> Html Msg
view model =
  let -- Buttons to enable and disable features
      buttons =
        div [] [ button [onClick EnableA] [text "Enable A"]
               , button [onClick DisableA] [text "Disable A"]
               , button [onClick EnableB] [text "Enable B"]
               , button [onClick DisableB] [text "Disable B"]
               ]

      -- All possible feature states
      aEnabled  = div [] [text "A enabled"]
      aDisabled = div [] [text "A disabled"]
      bEnabled  = div [] [text "B enabled"]
      bDisabled = div [] [text "B disabled"]
  in case model of
       NoneEnabled ->
         div [] [buttons, aDisabled, bDisabled]
       AEnabled ->
         div [] [buttons, aEnabled, bDisabled]
       BEnabled ->
         div [] [buttons, aDisabled, bEnabled]

update : Msg -> Model -> Model
update msg model =
  case (msg, model) of
    (EnableA, _) ->
      AEnabled
    (EnableB, _) ->
      BEnabled
    (DisableA, AEnabled) ->
      NoneEnabled
    (DisableB, BEnabled) ->
      NoneEnabled
    _ ->
      model

main : Program () Model Msg
main =
  Browser.sandbox { init = init, update = update, view = view }
Run Code Online (Sandbox Code Playgroud)

aEnabled,aDisabled,bEnabled,和bDisabled中的功能view是潜在的计算昂贵.无论分支case model of采用哪种分支,还是仅仅依赖于所评估的已使用功能,它们是否会被评估?

或用一个较短的例子措辞.

f c x =
  let a = x + 1
      b = x + 2
  in case c of
       True ->
         a
       False ->
         b
Run Code Online (Sandbox Code Playgroud)

f True 0强制b在let表达式中进行评估吗?

Cha*_*ert 5

榆树let/ in陈述没有被懒惰评估.你可以用一些Debug.log陈述来证明这一点:

f c x =
  let a = Debug.log "a calculated" <| x + 1
      b = Debug.log "b calculated" <| x + 2
  in case c of
       True ->
         a
       False ->
         b
Run Code Online (Sandbox Code Playgroud)

f无论输入如何,只调用一次会将两条消息都记录到控制台.这里的例子.

解决这个障碍的一种方法是为a和需要一个任意参数b,例如Unit ():

f c x =
  let a () = Debug.log "a calculated" <| x + 1
      b () = Debug.log "b calculated" <| x + 2
  in case c of
       True ->
         a ()
       False ->
         b ()
Run Code Online (Sandbox Code Playgroud)

这种变化只会评估功能a b.