Fork me on GitHub
Elm Copenhagen, February 2018 Meetup @MobileLife

Updated

With some input from Basile Henry, also attended the Meetup, I have made a few modifications to the code in order to support m :: * -> * ((a -> b) -> m a -> m b) as good as Elm allows us to do it, but without transitioning to a signature hell as seen in elm-data, see References for more information on that library.

Obviously not really monads

As a fellow Coding Pirates volunteer, Hans Bugge Grathwohl , pointed out:

1
2
3
4
5
6
7
8
9
10
11
odd :
{ fmap : (Int -> String) -> Float -> List Char
, join : List Char -> String
}
odd =
{ fmap = \f x -> String.toList (f (truncate x))
, join = String.fromList
}

weird : String
weird = 4.5 |> bind odd toString

this can’t really be considered monads as there is no relation between a and ma as well as mb and mmb.

Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
module Main exposing (..)

import Html exposing (br, div, text)


bind :
{ monad
| fmap : (a -> mb) -> ma -> mmb
, join : mmb -> mb
}
-> ((a -> mb) -> ma -> mb)
bind { fmap, join } f m =
join (fmap f m)


maybe :
{ fmap : (a -> b) -> Maybe a -> Maybe b
, join : Maybe (Maybe c) -> Maybe c
}
maybe =
{ fmap = Maybe.map
, join =
\mm ->
case mm of
Nothing ->
Nothing

Just m ->
m
}


list :
{ fmap : (a -> b) -> List a -> List b
, join : List (List c) -> List c
}
list =
{ fmap = List.map
, join = List.concat
}


result :
{ fmap : (a -> b) -> Result c a -> Result c b
, join : Result e (Result e d) -> Result e d
}
result =
{ fmap = Result.map
, join =
\mm ->
case mm of
Result.Err e ->
Result.Err e

Result.Ok m ->
m
}


foo : Maybe Int
foo =
Just 42
|> bind maybe (\x -> Just (x + 1))
|> bind maybe (\x -> Just (x + 1))
|> bind maybe (\x -> Just (x + 1))


bar : List String
bar =
[ 0, 1, 2, 4, 5 ]
|> bind list (\x -> [ x + 10, x + 20 ])
|> bind list (\x -> [ x + 100 ])
|> bind list (\x -> [ toString x ])


baz : Result String Int
baz =
Result.Ok " 42 "
|> bind result String.toInt
|> bind result (\x -> Result.Ok (x + 1))
|> bind result (\x -> Result.Ok (x + 1))
|> bind result (\x -> Result.Ok (x + 1))


qux : Result String Int
qux =
Result.Ok " 42 "
|> bind result (String.trim >> Result.Ok)
|> bind result String.toInt
|> bind result (\x -> Result.Ok (x + 1))
|> bind result (\x -> Result.Ok (x + 1))
|> bind result (\x -> Result.Ok (x + 1))


main =
div []
[ text <| "-- Maybe: " ++ toString foo
, br [] []
, text <| "-- Lists: " ++ toString bar
, br [] []
, text <| "-- Result: " ++ toString baz
, br [] []
, text <| "-- Result: " ++ toString qux
]

Code output:

-- Maybe: Just 45
-- Lists: ["110","120","111","121","112","122","114","124","115","125"]
-- Result: Err "could not convert string ' 42 ' to an Int"
-- Result: Ok 45

References:

comments powered by Disqus