Jeremy Fairbank
September 28, 2017
610

Elm Conf 2017: Solving the Boolean Identity Crisis

Jeremy Fairbank

September 28, 2017

Transcript

2. Software is broken. We are here to fix it. Say

[email protected]

}

11. { fetching: false, success: false, dog: null, error: true, errorMessage:

'Ruh roh!', }
12. { fetching: true, success: true, dog: { name: 'Tucker' },

error: true, errorMessage: 'Uh oh!', } ¯\_(ツ)_/¯ Invalid State
13. { fetching: true, success: true, dog: { name: 'Tucker' },

error: true, errorMessage: 'Uh oh!', } ¯\_(ツ)_/¯ Invalid State
14. if (props.error) { ... } else if (props.fetching) { ...

} else if (props.success) { ... } else { ... }

18. – Robert Harper “There is no information carried by a

Boolean beyond its value, and that’s the rub.”

23. Boolean Algebra George Boole x ∧ y x ∨ y

x ∨ (y ∧ z) ¬x
24. Boolean Values True && True True || False True ||

(True && False) not True

26. Premise 1: If it’s raining then it’s cloudy. Premise 2:

It’s raining. Conclusion: It’s cloudy. Propositional Logic
27. Premise 1: If it’s raining then it’s cloudy. Premise 2:

It’s raining. Conclusion: It’s cloudy. PROPOSITIONS
28. prop·o·si·tion a statement that expresses a concept that can be

true or false
29. Boolean ≠ Proposition A proposition, p, that is true is

not the same as saying p is equal to true.

35. bookFlight city isPremiumCustomer = if isPremiumCustomer then ... else ...

Regular customer?
36. viewOpacitySlider = viewSlider True viewVolumeSlider = viewSlider False view model

= div [] [ viewOpacitySlider , viewVolumeSlider ] ?

38. viewSlider msg isHorizontal = if isHorizontal then ... else ...

Implicit vertical slider
39. – Uncle Bob (Robert Martin) “Boolean arguments loudly declare that

the function does more than one thing. They are confusing and should be eliminated.”

= ...

= ...

= ...

46. bookFlight city isPremiumCustomer hasCheckedLuggage preferWindow = let luggageCost = if

hasCheckedLuggage then ... else ... in if isPremiumCustomer then if hasCheckedLuggage then ... else ... else if hasCheckedLuggage then ... else ...
47. – Martin Fowler “…an API should be written to make

it easier for the caller, so if we know where the caller is coming from we should design the API with that information in mind.”

50. bookFlight city customerType = case customerType of "Premium" -> ...

"Regular" -> ... _ -> ...
51. bookFlight city customerType = case customerType of "Premium" -> ...

"Regular" -> ... _ -> ...
52. bookFlight "St. Louis" "premium" bookFlight "St. Louis" "economical" bookFlight "St.

Louis" "" Primitive Obsession Revisited

54. type CustomerType = Premium | Regular bookFlight "St. Louis" Premium

bookFlight "St. Louis" Regular
55. bookFlight city customerType = case customerType of Premium -> ...

Regular -> ...
56. type Angle = Degrees Float | Radians Float rotateFuelRod fuelRod

(Degrees 30) rotateControlRod controlRod (Radians pi)
57. rotateFuelRod fuelRod angle = case angle of Degrees amount ->

... Radians amount -> ... rotateControlRod controlRod angle = case angle of Degrees amount -> ... Radians amount -> ...
58. rotate rod angle = case angle of Degrees amount ->

... Radians amount -> ...
59. rotate rod angle = case angle of Degrees amount ->

... Radians amount -> ...

62. rotate rod angle = case angle of Degrees amount ->

rotateInDegrees rod amount Radians amount -> rotateInRadians rod amount

65. time = if doYouKnowTheTime person then tellMeTheTime person else """

Does anybody really know what time it is? """
66. time = if doYouKnowTheTime person then tellMeTheTime person else """

Does anybody really know what time it is? """
67. time = if doYouKnowTheTime person then tellMeTheTime person else """

Does anybody really know what time it is? """
68. time = if doYouKnowTheTime person then tellMeTheTime person else """

Does anybody really know what time it is? """

person

71. – Conor McBride “To make use of a Boolean you

have to know its provenance so that you can know what it means.”

74. function findDogByName(name, dogs) { if (name in dogs) { return

`\${name} is a \${dogs[name].breed}`; } else { return 'Heck! No pupper found.'; } }
75. findDogByName name dogs = if Dict.member name dogs then case

Dict.get name dogs of Just dog -> name ++ " is a " ++ dog.breed Nothing -> "Heck! No pupper found." else "Heck! No pupper found."
76. findDogByName name dogs = if Dict.member name dogs then case

Dict.get name dogs of Just dog -> name ++ " is a " ++ dog.breed Nothing -> "Heck! No pupper found." else "Heck! No pupper found."
77. findDogByName name dogs = if Dict.member name dogs then case

Dict.get name dogs of Just dog -> name ++ " is a " ++ dog.breed Nothing -> "Heck! No pupper found." else "Heck! No pupper found."
78. canDivide numerator denominator = denominator /= 0 divisionResult numerator denominator

= if canDivide numerator denominator then "The result is " ++ toString (numerator / denominator) else "Could not divide"
79. canDivide numerator denominator = denominator /= 0 divisionResult numerator denominator

= if canDivide numerator denominator then "The result is " ++ toString (numerator / denominator) else "Could not divide"
80. divisionResult numerator denominator = if canDivide numerator denominator then "The

result is " ++ toString (numerator / denominator) else "The result is " ++ toString (numerator / denominator)

you see.”

83. findDogByName name dogs = case Dict.get name dogs of Just

dog -> name ++ " is a " ++ dog.breed Nothing -> "Heck! No pupper found."

...

...
86. type TellTime = Time String | NoWatch | NoPhone |

NoSundial case whatTimeIsIt person of Time time -> ... NoWatch -> ... NoPhone -> ... NoSundial -> ...
87. divide numerator denominator = case denominator of 0 -> Err

"Divide by zero" _ -> Ok (numerator / denominator) divisionResult numerator denominator = case divide 4 2 of Ok result -> "The result is " ++ toString result Err error -> "Could not divide: " ++ error

89. { fetching = False , success = True , dog

= Just { name = "Tucker" } , error = False , errorMessage = "" } Back to State
90. if model.error then ... else if model.fetching then ... else

if model.success then ... else ...

...
92. { fetching = True , success = True , dog

= { name = "Tucker" } , error = True , errorMessage = "Uh oh!" }

95. type RemoteDoggo = Ready | Fetching | Success Dog |

Error String type alias Model = { dog : RemoteDoggo , ... }
96. type RemoteDoggo = Ready | Fetching | Success Dog |

Error String type alias Model = { dog : RemoteDoggo , ... }
97. type RemoteDoggo = Ready | Fetching | Success Dog |

Error String type alias Model = { dog : RemoteDoggo , ... }
98. type RemoteDoggo = Ready | Fetching | Success Dog |

Error String type alias Model = { dog : RemoteDoggo , ... }
99. { dog = Ready, ... } { dog = Fetching,

... } { dog = Success { name = "Tucker" }, ... } { dog = Error "Uh oh!", ... }
100. view : Model -> Html Msg view model = case

model.dog of Ready -> viewFindDog model Fetching -> viewSpinner Success dog -> viewDog dog Error error -> viewError error
101. view : Model -> Html Msg view model = case

model.dog of Ready -> viewFindDog model Fetching -> viewSpinner Success dog -> viewDog dog -- Error error -> viewError error
102. This `case` does not have branches for all possibilities. 47|>

case model.dog of 48|> Ready -> viewFindDog model 49|> 50|> Fetching -> viewSpinner 51|> 52|> Success dog -> viewDog dog You need to account for the following values: Main.Error _ Add a branch to cover this pattern!
103. package.elm-lang.org/packages/krisajenkins/remotedata/latest type RemoteData e a = NotAsked | Loading |

Failure e | Success a
104. package.elm-lang.org/packages/krisajenkins/remotedata/latest type RemoteData e a = NotAsked | Loading |

Failure e | Success a
105. package.elm-lang.org/packages/krisajenkins/remotedata/latest type RemoteData e a = NotAsked | Loading |

Failure e | Success a
106. type alias Todo = { isComplete : Bool , isEditing

: Bool } type alias Customer = { isPlatinum : Bool , isGold : Bool , isSilver : Bool }
107. type TodoStatus = Complete | Editing type alias Todo =

{ status : TodoStatus }
108. type AccountType = Platinum | Gold | Silver type alias

Customer = { accountType : AccountType }

Feldman

for users

120. Save to archive Save to inbox Verb labels = when

will it happen?
121. Saved to archive Saved to inbox Adjective labels = describe

the final result.