ondrej
July 4, 2019, 10:26am
1
Hi, I’m curious what’s your preferred way to provide default values to functions.
One example from JS world
let defaultOptions = {
optionA: 'A',
optionB: 'B',
optionC: 'C'
};
function myFn(options) {
options = Object.assing({}, defaultOptions, options);
...
}
myFn({ optionB: 'D'});
https://ellie-app.com/5ZbNh2XFBdfa1
In Elm, I’m forced to state all the options when calling myFn
, otherwise it won’t compile. Is there any nice patter how to provide override for default options?
Thank you
You can use the record update syntax for that, so your code in the Ellie would look like
{ defaultOptions | optionB = "D" }
2 Likes
My favorite is the Optionals -> Optionals
pattern, which I learned from @dillonkearns
Here’s an example for a text input
type alias Required msg =
{ onInput : String -> msg
, value : String
, placeholder : String
}
type alias Optionals msg =
{ attrs : List (Attribute msg)
, onEnter : Maybe msg
, leftDecoration : Html msg
, rightDecoration : Html msg
, id : String
}
defaults : Optionals msg
defaults =
{ attrs = []
, onEnter = Nothing
, leftDecoration = none
, rightDecoration = none
, id = ""
}
textInput: Required msg -> (Optionals msg -> Optionals msg) -> Html msg
textInput required optionals =
let
opts =
optionals defaults
in...
You then call the function like this:
textInput
{ onInput = Input, value = model.string, placeholder = "Type something" }
(\d -> { d | onEnter = Just Submit, attrs = [ class "stuff" ] })
And if you don’t want to set any optional arguments at all, you use the identity
function:
textInput
{ onInput = Input, value = model.string, placeholder = "Type something" }
identity
2 Likes
You can watch this talk:
which essentially shows various ways to solve this problem. Here are the basics:
--- many functions
defaultFoo : Required -> Foo
barredFoo : Bar -> Required -> Foo
barredAndBazzedFoo : Bar -> Baz -> Required -> Foo
customFoo : { bar : Bar, baz : Baz, qux: Int, required : Required } -> Foo
--- default options
type alias Options =
{ bar : Bar
, baz : Baz
, qux: Int
}
defaultFooOptions : Options
defaultFooOptions =
{ bar = defaultBar
, baz = defaultBaz
, qux = 0
}
foo : Options -> Required -> Foo
--call with
foo { defaultFooOptions | qux = 3 } required
--- Options list
type Option
= Bar Bar
| Baz Baz
| Qux Int
qux : Int -> Option -- etc
foo : List Option -> Required -> Foo
-- call with
foo [ qux 4 ] required
-- with pattern
type Builder
init : Required -> Builder
withBar : Bar -> Builder -> Builder
withBaz : Baz -> Builder -> Builder
withQux : Int -> Builder -> Builder
toFoo : Builder -> Foo
-- call with
init required
|> withQux 4
|> toFoo
Watch the talk so see some of the pros/cons of these approaches.
7 Likes
system
Closed
July 14, 2019, 11:34am
5
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.