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:
References:
- Continuational. Lots of code, few words (Joakim Ahnfelt-Rønne blog):
- elm-data: Experimental implementation of generic operations for elm.
- elm-lang: Documentation