Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
intro-to-fp
short-exercises
Commits
4fa22fbb
Commit
4fa22fbb
authored
Jun 24, 2019
by
crater2150
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[lec09] Adding Readers, Writers and State Randoms
parent
145200df
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
286 additions
and
0 deletions
+286
-0
README.md
README.md
+1
-0
src/main/scala/readerwriter/Randoms.scala
src/main/scala/readerwriter/Randoms.scala
+34
-0
src/main/scala/readerwriter/Readers.scala
src/main/scala/readerwriter/Readers.scala
+25
-0
src/main/scala/readerwriter/Writers.scala
src/main/scala/readerwriter/Writers.scala
+39
-0
src/main/scala/readerwriter/internal/Reader.scala
src/main/scala/readerwriter/internal/Reader.scala
+23
-0
src/main/scala/readerwriter/internal/State.scala
src/main/scala/readerwriter/internal/State.scala
+21
-0
src/main/scala/readerwriter/internal/Writer.scala
src/main/scala/readerwriter/internal/Writer.scala
+27
-0
src/main/scala/util/package.scala
src/main/scala/util/package.scala
+10
-0
src/test/scala/readerwriter/RandomSpec.scala
src/test/scala/readerwriter/RandomSpec.scala
+18
-0
src/test/scala/readerwriter/ReaderSpec.scala
src/test/scala/readerwriter/ReaderSpec.scala
+31
-0
src/test/scala/readerwriter/WriterSpec.scala
src/test/scala/readerwriter/WriterSpec.scala
+57
-0
No files found.
README.md
View file @
4fa22fbb
...
...
@@ -19,6 +19,7 @@ usually marked with `???`.
| 6: Typeclasses |
[
`typeclasses`
](
src/main/scala/typeclasses/
)
|
`testOnly typeclasses.*`
(needs some uncommenting)
| 7: Monads |
[
`monads`
](
src/main/scala/monads/
)
|
`testOnly monads.*`
(needs some uncommenting)
| 8: Applicative Functors |
[
`applicative`
](
src/main/scala/applicative/
)
|
`testOnly applicative.*`
(needs some uncommenting)
| 8: Algebraic View on more Monads|
[
`readerwriter`
](
src/main/scala/readerwriter/
)
|
`testOnly readerwriter.*`
## Usage tips:
To keep your local solutions to the exercises when pulling from the repository,
...
...
src/main/scala/readerwriter/Randoms.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter
import
readerwriter.internal.State
,
State
.
_
import
util._
object
Randoms
{
def
threeInts
:
State
[
RNG
,
(
Int
,
Int
,
Int
)]
=
???
/*@formatter:off*/
def
randomInt
:
State
[
RNG
,
Int
]
=
for
{
rng
<-
get
[
RNG
]
(
rng2
,
i
)
=
rng
.
nextInt
_
<-
set
(
rng2
)
}
yield
i
/*@formatter:on*/
def
nonNegativeInt
:
State
[
RNG
,
Int
]
=
for
{
i
<-
randomInt
}
yield
if
(
i
<
0
)
-(
i
+
1
)
else
i
}
trait
RNG
{
def
nextInt
:
(
RNG
,
Int
)
}
case
class
Simple
(
seed
:
Long
)
extends
RNG
{
def
nextInt
:
(
RNG
,
Int
)
=
{
val
newSeed
=
(
seed
*
0x5DEECE66D
L
+
0xB
L
)
&
0xFFFFFFFFFFFF
L
val
nextRNG
=
Simple
(
newSeed
)
val
n
=
(
newSeed
>>>
16
).
toInt
(
nextRNG
,
n
)
}
}
src/main/scala/readerwriter/Readers.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter
import
java.time.LocalDate
import
readerwriter.internal.Reader
,
Reader
.
_
import
util._
final
case
class
Request
(
user
:
Option
[
String
],
locale
:
String
,
route
:
String
,
params
:
Map
[
String
,
List
[
String
]],
now
:
LocalDate
,
)
object
Readers
{
/* everything required to use ask and the monad operations
* is already imported */
def
formatUser
:
Reader
[
Request
,
String
]
=
???
def
formatTime
:
Reader
[
Request
,
String
]
=
???
def
sayBye
:
Reader
[
Request
,
String
]
=
???
}
src/main/scala/readerwriter/Writers.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter
import
readerwriter.internal.Writer
,
Writer
.
_
import
util._
object
Writers
{
/* everything required to use tell and the monad operations
* is already imported */
def
collatzDepth
(
n
:
Int
)
:
Writer
[
List
[
String
]
,
Int
]
=
???
def
collatzSearch
(
start
:
Int
,
limit
:
Int
)
:
Writer
[
List
[
String
]
,
Int
]
=
???
}
object
CollatzWithoutWriter
{
def
collatzDepth
(
n
:
Int
)
:
(
List
[
String
],
Int
)
=
if
(
n
==
1
)
(
List
(
"got 1, doing nothing"
),
0
)
else
if
(
n
%
2
==
0
)
{
val
(
way
,
depth
)
=
collatzDepth
(
n
/
2
)
(
s
"got $n, halving"
::
way
,
depth
+
1
)
}
else
{
val
(
way
,
depth
)
=
collatzDepth
(
n
*
3
+
1
)
(
s
"got $n, tripling plus one"
::
way
,
depth
+
1
)
}
def
collatzSearch
(
start
:
Int
,
limit
:
Int
)
:
(
List
[
String
],
Int
)
=
{
val
(
way
,
depth
)
=
collatzDepth
(
start
)
if
(
depth
<
limit
)
{
val
(
way2
,
number
)
=
collatzSearch
(
start
+
1
,
limit
)
(
s
"testing $start"
::
way
++
(
s
"depth was $depth"
::
way2
),
number
)
}
else
(
s
"testing $start"
::
way
++
List
(
s
"depth was $depth"
,
s
"returning $start"
),
start
)
}
}
src/main/scala/readerwriter/internal/Reader.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter.internal
import
applicative.Monad
case
class
Reader
[
R
,
A
](
run
:
R
=>
A
)
object
Reader
{
def
ask
[
R
]
:
Reader
[
R
,
R
]
=
Reader
(
x
=>
x
)
implicit
def
readerM
[
R
]
:
Monad
[
Reader
[
R
,
?
]]
=
new
Monad
[
Reader
[
R
,
?
]]
{
override
def
flatMap
[
A
,
B
](
fa
:
Reader
[
R
,
A
])(
f
:
A
=>
Reader
[
R
,
B
])
:
Reader
[
R
,
B
]
=
Reader
(
in
=>
{
val
a
=
fa
.
run
(
in
)
f
(
a
).
run
(
in
)
})
override
def
unit
[
A
](
a
:
A
)
:
Reader
[
R
,
A
]
=
Reader
(
_
=>
a
)
override
def
map2
[
A
,
B
,
C
](
fa
:
Reader
[
R
,
A
],
fb
:
Reader
[
R
,
B
])(
f
:
(
A
,
B
)
=>
C
)
:
Reader
[
R
,
C
]
=
Reader
(
in
=>
{
val
a
=
fa
.
run
(
in
)
val
b
=
fb
.
run
(
in
)
f
(
a
,
b
)
})
override
def
map
[
A
,
B
](
fa
:
Reader
[
R
,
A
])(
f
:
A
=>
B
)
:
Reader
[
R
,
B
]
=
Reader
(
in
=>
f
(
fa
.
run
(
in
)))
}
}
src/main/scala/readerwriter/internal/State.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter.internal
/* You don't need to edit any of the files inside this package. These are the actual implementations, and you should
* only use the provided methods, not rely on internal structure
*/
import
applicative.Monad
case
class
State
[
S
,
A
]
private
(
run
:
S
=>
(
S
,
A
))
case
object
State
{
implicit
def
stateMonad
[
S
]
:
Monad
[
State
[
S
,
?
]]
=
new
Monad
[
State
[
S
,
?
]]
{
override
def
unit
[
A
](
a
:
A
)
:
State
[
S
,
A
]
=
State
(
s
=>
(
s
,
a
))
override
def
flatMap
[
A
,
B
](
fa
:
State
[
S
,
A
])(
f
:
A
=>
State
[
S
,
B
])
:
State
[
S
,
B
]
=
State
(
s
=>
{
val
(
s1
,
a
)
=
fa
.
run
(
s
)
f
(
a
).
run
(
s1
)
})
}
def
get
[
S
]
:
State
[
S
,
S
]
=
State
(
s
=>
(
s
,
s
))
def
set
[
S
](
s
:
S
)
:
State
[
S
,
Unit
]
=
State
(
_
=>
(
s
,
()))
}
src/main/scala/readerwriter/internal/Writer.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter.internal
import
algebra.Monoid
import
applicative.Monad
final
case
class
Writer
[
L
,
A
](
v
:
(
L
,
A
))
object
Writer
{
implicit
def
listMonoid
[
A
]
:
Monoid
[
List
[
A
]]
=
new
Monoid
[
List
[
A
]]
{
def
zero
:
List
[
Nothing
]
=
List
.
empty
def
op
(
l1
:
List
[
A
],
l2
:
List
[
A
])
:
List
[
A
]
=
l1
++
l2
}
def
tell
[
L
](
l
:
L
)
:
Writer
[
L
,
Unit
]
=
Writer
((
l
,
()))
implicit
def
writerM
[
L:
Monoid
]
:
Monad
[
Writer
[
L
,
?
]]
=
new
Monad
[
Writer
[
L
,
?
]]
{
override
def
flatMap
[
A
,
B
](
fa
:
Writer
[
L
,
A
])(
f
:
A
=>
Writer
[
L
,
B
])
:
Writer
[
L
,
B
]
=
{
val
next
=
f
(
fa
.
v
.
_2
)
Writer
((
implicitly
[
Monoid
[
L
]].
op
(
fa
.
v
.
_1
,
next
.
v
.
_1
),
next
.
v
.
_2
))
}
def
unit
[
A
](
a
:
A
)
:
Writer
[
L
,
A
]
=
Writer
((
implicitly
[
Monoid
[
L
]].
zero
,
a
))
override
def
map2
[
A
,
B
,
C
](
fa
:
Writer
[
L
,
A
],
fb
:
Writer
[
L
,
B
])(
f
:
(
A
,
B
)
=>
C
)
:
Writer
[
L
,
C
]
=
Writer
((
implicitly
[
Monoid
[
L
]].
op
(
fa
.
v
.
_1
,
fb
.
v
.
_1
),
f
(
fa
.
v
.
_2
,
fb
.
v
.
_2
)))
override
def
map
[
A
,
B
](
fa
:
Writer
[
L
,
A
])(
f
:
A
=>
B
)
:
Writer
[
L
,
B
]
=
Writer
((
fa
.
v
.
_1
,
f
(
fa
.
v
.
_2
)))
}
}
src/main/scala/util/package.scala
0 → 100644
View file @
4fa22fbb
import
applicative.Monad
import
scala.language.higherKinds
package
object
util
{
implicit
class
MonadOps
[
F
[
_
]
:
Monad
,
A
](
fa
:
F
[
A
])
{
def
flatMap
[
B
](
f
:
A
=>
F
[
B
])
:
F
[
B
]
=
implicitly
[
Monad
[
F
]].
flatMap
(
fa
)(
f
)
def
map
[
B
](
f
:
A
=>
B
)
:
F
[
B
]
=
implicitly
[
Monad
[
F
]].
map
(
fa
)(
f
)
}
}
src/test/scala/readerwriter/RandomSpec.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter
import
org.scalatest._
import
testutil.PendingIfUnimplemented
class
RandomSpec
extends
FlatSpec
with
Matchers
with
AppendedClues
with
PendingIfUnimplemented
{
val
initial
=
Simple
(
192837465L
)
val
(
r1
,
i1
)
=
initial
.
nextInt
val
(
r2
,
i2
)
=
r1
.
nextInt
val
(
r3
,
i3
)
=
r2
.
nextInt
"threeInts"
should
"have the same result as passing state manually"
in
{
Randoms
.
threeInts
.
run
(
initial
).
_2
shouldBe
((
i1
,
i2
,
i3
))
}
it
should
"result in the same rng state as passing state manually"
in
{
Randoms
.
threeInts
.
run
(
initial
).
_1
shouldBe
r3
}
}
src/test/scala/readerwriter/ReaderSpec.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter
import
org.scalatest._
import
testutil.PendingIfUnimplemented
import
java.time.LocalDate
class
ReaderSpec
extends
FlatSpec
with
Matchers
with
AppendedClues
with
PendingIfUnimplemented
{
val
exampleRequest
=
Request
(
Some
(
"Mister X"
),
"de-DE"
,
"/hello"
,
Map
(),
LocalDate
.
of
(
2019
,
6
,
26
)
)
val
noUserRequest
=
exampleRequest
.
copy
(
user
=
None
)
"formatUser"
should
"read the username or substitute \"anonymous\""
in
{
Readers
.
formatUser
.
run
(
exampleRequest
)
shouldBe
"Mister X"
Readers
.
formatUser
.
run
(
noUserRequest
)
shouldBe
"anonymous"
}
"formatTime"
should
"output the string representation of a request date"
in
{
Readers
.
formatTime
.
run
(
exampleRequest
)
shouldBe
"2019-06-26"
}
"sayBye"
should
"contain the correct user name and date"
in
{
Readers
.
sayBye
.
run
(
exampleRequest
)
shouldBe
"Goodbye Mister X, today is 2019-06-26"
}
}
src/test/scala/readerwriter/WriterSpec.scala
0 → 100644
View file @
4fa22fbb
package
readerwriter
import
java.time.LocalDate
import
org.scalatest._
import
testutil.PendingIfUnimplemented
class
WriterSpec
extends
FlatSpec
with
Matchers
with
AppendedClues
with
PendingIfUnimplemented
{
"collatzDepth"
should
"keep a log of the search"
in
{
val
(
log
,
_
)
=
Writers
.
collatzDepth
(
3
).
v
log
shouldBe
List
(
"got 3, tripling plus one"
,
"got 10, halving"
,
"got 5, tripling plus one"
,
"got 16, halving"
,
"got 8, halving"
,
"got 4, halving"
,
"got 2, halving"
,
"got 1, doing nothing"
,
)
}
it
should
"return the right depth"
in
{
val
(
_
,
depth
)
=
Writers
.
collatzDepth
(
3
).
v
depth
shouldBe
7
}
"collatzSearch"
should
"keep a log, together with collatzDepth"
in
{
val
(
log
,
_
)
=
Writers
.
collatzSearch
(
1
,
5
).
v
log
shouldBe
List
(
"testing 1"
,
"got 1, doing nothing"
,
"depth was 0"
,
"testing 2"
,
"got 2, halving"
,
"got 1, doing nothing"
,
"depth was 1"
,
"testing 3"
,
"got 3, tripling plus one"
,
"got 10, halving"
,
"got 5, tripling plus one"
,
"got 16, halving"
,
"got 8, halving"
,
"got 4, halving"
,
"got 2, halving"
,
"got 1, doing nothing"
,
"depth was 7"
,
"returning 3"
,
)
}
it
should
"find the smallest number with at least given depth"
in
{
val
(
_
,
res
)
=
Writers
.
collatzSearch
(
1
,
5
).
v
res
shouldBe
3
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment