Does the underscore short-circuit

I am trying to replicate the short-circuiting behaviour of (&&). Would Elm translate this code to only evaluate the second argument if the first were True?

(&&) : Bool -> Bool -> Bool
(&&) a =
    case a of
        False -> \_ -> False
        True -> id

The documentation says AFAIK “discards the input”. Is the elm/compiler optimizing it then as shortcircuit?
If it doesn’t, how could I implement short circuiting as frictionless as possibe? The best I could come up with is:

type Bool = Bool BVal
type BVal 
    = True
    | False

true : Bool
true = Bool True

false : Bool
false = Bool False
    
(&&) : Bool -> Bool -> Bool
(&&) (Bool a) =
    case a of
        False -> \_ -> Bool False
        True -> id

but that’s rather ugly IMO and causes horrible code.

I have been digging in elm/compiler for two hours right now, and am unable to test/verify my assumption.

Context: elm-in-elm Issue

No, it doesn’t short-circuit. You can try it out like this:

https://ellie-app.com/fLgLnwsQjyJa1

Debug.log is quite a useful tool to figure out if something gets executed or not.

I’m afraid the only option is to use explicit thunks.

i.e.

(&&) : Bool -> (() -> Bool) -> Bool

Thanks for the quick reply!
Nice trick with Debug.log, why didn’t I come up with it? :man_facepalming:

and : Bool -> (() -> Bool) -> Bool
and a b =
    case a of
        False ->
            False

        True ->
            b ()

would be your implementation? Isn’t that basically how lazy works :stuck_out_tongue_winking_eye:?

So the second Bool needs always an lambda prepended? as in

and (isShining sun) 
    (\() -> isGreen grass)

or can I somehow wrap the lambda expression away?

lazy : a -> () -> a
lazy x () = x

and (isShining sun) 
    (lazy <| isGreen grass)

causes x to be evaluated directly again, doesn’t it?

Yeah I’m afraid there isn’t much of a way to get from explicit thunks if you want to control when stuff is evaluated.