在 Elm 的绑定中是否允许进入惰性?
Is let-in lazy in its bindings in Elm?
我有两个功能 A 和 B,可以同时禁用、启用 A、启用 B,但不能同时启用。看完后 Making Impossible States Impossible 我想尝试在类型级别上强制执行此操作。
我正在考虑的解决方案的简化版本如下。
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 }
我的 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
f True 0
会在 let 表达式中强制计算 b
吗?
Elm 的 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
只调用一次 f
会将两条消息都记录到控制台,而不管输入是什么。 Example here.
绕过这个障碍的一种方法是要求 a
和 b
的任意参数,例如单位 ()
:
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 ()
此变体将仅计算函数 a
或 b
.
我有两个功能 A 和 B,可以同时禁用、启用 A、启用 B,但不能同时启用。看完后 Making Impossible States Impossible 我想尝试在类型级别上强制执行此操作。
我正在考虑的解决方案的简化版本如下。
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 }
我的 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
f True 0
会在 let 表达式中强制计算 b
吗?
Elm 的 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
只调用一次 f
会将两条消息都记录到控制台,而不管输入是什么。 Example here.
绕过这个障碍的一种方法是要求 a
和 b
的任意参数,例如单位 ()
:
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 ()
此变体将仅计算函数 a
或 b
.