-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathFormatter.swift
165 lines (131 loc) · 4.44 KB
/
Formatter.swift
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
A formatter. The `Result` type means the returned value at the end. The more formatters you compose, the
more this will build up arguments. _E.g._, from `Result` to `(Int) -> Result` to
`(Character) -> (Int) -> Result`, etc.
*/
public struct Formatter<Result, A> {
public let format: (@escaping (String) -> Result) -> A
}
/**
A formatter that transforms `Input` into `Result`.
*/
public typealias FormatterOf<Input, Result> = Formatter<Result, (Input) -> Result>
/**
Run the formatter to produce a `String` value.
*/
public func format<A>(_ formatter: Formatter<String, A>) -> A {
return formatter.format { string in string }
}
// MARK:
/**
Composition operator. Combines two formatters.
- parameters:
- lhs: a formatter
- rhs: a formatter
- returns: A formatter combining the left-hand side with the right-hand side.
*/
public func % <A, B, C>(lhs: Formatter<B, A>, rhs: Formatter<C, B>) -> Formatter<C, A> {
return Formatter { stringToResult in
lhs.format { leftString in
rhs.format { rightString in
stringToResult(leftString + rightString)
}
}
}
}
private func s<A>(_ string: String) -> Formatter<A, A> {
return Formatter { stringToResult in stringToResult(string) }
}
/**
Composition operator. Combines a formatter and a string.
format(int % " luftballons")(99)
// "99 luftballons"
- parameters:
- lhs: a formatter
- rhs: a string
- returns: A formatter appending the given formatter with the given string.
*/
public func % <R, A>(lhs: Formatter<R, A>, rhs: String) -> Formatter<R, A> {
return lhs % s(rhs)
}
/**
Composition operator. Combines a string and a formatter.
format("hello " % string)("world")
// "hello world"
- parameters:
- lhs: a string
- rhs: a formatter
- returns: A formatter with the given string prepended to the given formatter.
*/
public func % <R, A>(lhs: String, rhs: Formatter<R, A>) -> Formatter<R, A> {
return s(lhs) % rhs
}
// MARK:
/**
Monoidal composition. Will append previous formatter input to the right-hand formatter.
format("It's day " % D % " of " <> y % ".")(Date())
// "It's day 180 of 2016."
- parameters:
- lhs: a formatter
- rhs: a formatter of the same type
- returns: A combined formatter matching the types of the given formatters.
*/
public func <> <R, A>(lhs: FormatterOf<R, A>, rhs: FormatterOf<R, A>) -> FormatterOf<R, A> {
return Formatter { stringToResult in
{ input in
lhs.format { leftString in
rhs.format { rightString in
stringToResult(leftString + rightString)
}(input)
}(input)
}
}
}
// MARK:
/**
Function compose two formatters. Will feed the result of one formatter into another.
format(left(2, "0") .% hex)(10)
// "0a"
- parameters:
- lhs: a formatter that takes a string
- rhs: a formatter
*/
public func .% <A, B, C>(lhs: Formatter<C, (String) -> B>, rhs: Formatter<B, A>) -> Formatter<C, A> {
return Formatter { stringToResult in rhs.format(lhs.format(stringToResult)) }
}
// MARK:
// paren-reducing overloads: these can go away when generic accessors (_e.g._, `var string<A>`) are supported
public func format<A>(_ formatter: () -> Formatter<String, A>) -> A {
return formatter().format { $0 }
}
public func % <R, A>(lhs: () -> Formatter<R, A>, rhs: String) -> Formatter<R, A> {
return lhs() % s(rhs)
}
public func % <R, A>(lhs: String, rhs: () -> Formatter<R, A>) -> Formatter<R, A> {
return s(lhs) % rhs()
}
public func % <A, B, C>(lhs: Formatter<B, A>, rhs: () -> Formatter<C, B>) -> Formatter<C, A> {
return lhs % rhs()
}
public func % <A, B, C>(lhs: () -> Formatter<B, A>, rhs: Formatter<C, B>) -> Formatter<C, A> {
return lhs() % rhs
}
public func <> <R, A>(lhs: () -> FormatterOf<R, A>, rhs: FormatterOf<R, A>) -> FormatterOf<R, A> {
return lhs() <> rhs
}
public func <> <R, A>(lhs: FormatterOf<R, A>, rhs: () -> FormatterOf<R, A>) -> FormatterOf<R, A> {
return lhs <> rhs()
}
public func <> <R, A>(lhs: () -> FormatterOf<R, A>, rhs: () -> FormatterOf<R, A>) -> FormatterOf<R, A> {
return lhs() <> rhs()
}
public func .% <A, B, C>(lhs: () -> Formatter<C, (String) -> B>, rhs: Formatter<B, A>) -> Formatter<C, A> {
return lhs() .% rhs
}
public func .% <A, B, C>(lhs: Formatter<C, (String) -> B>, rhs: () -> Formatter<B, A>) -> Formatter<C, A> {
return lhs .% rhs()
}
public func .% <A, B, C>(lhs: () -> Formatter<C, (String) -> B>, rhs: () -> Formatter<B, A>)
-> Formatter<C, A> {
return lhs() .% rhs()
}