Skip to content

Commit

Permalink
fix: add more mostly-adequate examples and solutions
Browse files Browse the repository at this point in the history
Signed-off-by: Dr. Carsten Leue <[email protected]>
  • Loading branch information
CarstenLeue committed Sep 7, 2023
1 parent 3ccafb5 commit fb91fd5
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 6 deletions.
7 changes: 7 additions & 0 deletions record/generic/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,13 @@ func MapRefWithIndex[M ~map[K]V, N ~map[K]R, K comparable, V, R any](f func(K, *
return F.Bind2nd(MonadMapRefWithIndex[M, N, K, V, R], f)
}

func MonadLookup[M ~map[K]V, K comparable, V any](m M, k K) O.Option[V] {
if val, ok := m[k]; ok {
return O.Some(val)
}
return O.None[V]()
}

func Lookup[M ~map[K]V, K comparable, V any](k K) func(M) O.Option[V] {
n := O.None[V]()
return func(m M) O.Option[V] {
Expand Down
5 changes: 5 additions & 0 deletions record/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ func Lookup[V any, K comparable](k K) func(map[K]V) O.Option[V] {
return G.Lookup[map[K]V](k)
}

// MonadLookup returns the entry for a key in a map if it exists
func MonadLookup[V any, K comparable](m map[K]V, k K) O.Option[V] {
return G.MonadLookup[map[K]V](m, k)
}

// Has tests if a key is contained in a map
func Has[K comparable, V any](k K, r map[K]V) bool {
return G.Has(k, r)
Expand Down
37 changes: 37 additions & 0 deletions samples/mostly-adequate/chapter09_monadiconions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ package mostlyadequate
import (
"fmt"
"path"
"regexp"

A "github.com/IBM/fp-go/array"
E "github.com/IBM/fp-go/either"
"github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/io"
IOE "github.com/IBM/fp-go/ioeither"
O "github.com/IBM/fp-go/option"
S "github.com/IBM/fp-go/string"
)
Expand Down Expand Up @@ -104,6 +108,21 @@ var (

// pureLog :: String -> IO ()
pureLog = io.Logf[string]("%s")

// addToMailingList :: Email -> IOEither([Email])
addToMailingList = F.Flow2(
A.Of[string],
IOE.Of[error, []string],
)

// validateEmail :: Email -> Either error Email
validateEmail = E.FromPredicate(Matches(regexp.MustCompile(`\S+@\S+\.\S+`)), errors.OnSome[string]("email %s is invalid"))

// emailBlast :: [Email] -> IO ()
emailBlast = F.Flow2(
A.Intercalate(S.Monoid)(","),
IOE.Of[error, string],
)
)

func Example_street() {
Expand Down Expand Up @@ -147,3 +166,21 @@ func Example_solution09B() {
// Output:
// ch09.md
}

func Example_solution09C() {

// // joinMailingList :: Email -> Either String (IO ())
joinMailingList := F.Flow4(
validateEmail,
IOE.FromEither[error, string],
IOE.Chain(addToMailingList),
IOE.Chain(emailBlast),
)

fmt.Println(joinMailingList("[email protected]")())
fmt.Println(joinMailingList("notanemail")())

// Output:
// Right[<nil>, string]([email protected])
// Left[*errors.errorString, string](email notanemail is invalid)
}
112 changes: 106 additions & 6 deletions samples/mostly-adequate/chapter10_applicativefunctor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,53 @@ import (
R "github.com/IBM/fp-go/context/readerioeither"
H "github.com/IBM/fp-go/context/readerioeither/http"
F "github.com/IBM/fp-go/function"
IOO "github.com/IBM/fp-go/iooption"
N "github.com/IBM/fp-go/number"
O "github.com/IBM/fp-go/option"
M "github.com/IBM/fp-go/record"
T "github.com/IBM/fp-go/tuple"
)

type PostItem struct {
UserId uint `json:"userId"`
Id uint `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
type (
PostItem struct {
UserId uint `json:"userId"`
Id uint `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}

Player struct {
Id int
Name string
}

LocalStorage = map[string]Player
)

var (
localStorage = LocalStorage{
"player1": Player{
Id: 1,
Name: "Albert",
},
"player2": Player{
Id: 2,
Name: "Theresa",
},
}

// getFromCache :: String -> IO User
getFromCache = func(name string) IOO.IOOption[Player] {
return func() O.Option[Player] {
return M.MonadLookup(localStorage, name)
}
}

// game :: User -> User -> String
game = F.Curry2(func(a, b Player) string {
return fmt.Sprintf("%s vs %s", a.Name, b.Name)
})
)

func getTitle(item PostItem) string {
return item.Title
Expand Down Expand Up @@ -71,3 +110,64 @@ func Example_renderPage() {
// Right[<nil>, string](<div>Destinations: [qui est esse], Events: [ea molestias quasi exercitationem repellat qui ipsa sit aut]</div>)

}

func Example_solution10A() {
safeAdd := F.Curry2(func(a, b O.Option[int]) O.Option[int] {
return F.Pipe3(
N.Add[int],
O.Of[func(int) func(int) int],
O.Ap[func(int) int](a),
O.Ap[int](b),
)
})

fmt.Println(safeAdd(O.Of(2))(O.Of(3)))
fmt.Println(safeAdd(O.None[int]())(O.Of(3)))
fmt.Println(safeAdd(O.Of(2))(O.None[int]()))

// Output:
// Some[int](5)
// None[int]
// None[int]
}

func Example_solution10B() {

safeAdd := F.Curry2(T.Untupled2(F.Flow2(
O.SequenceTuple2[int, int],
O.Map(T.Tupled2(N.MonoidSum[int]().Concat)),
)))

fmt.Println(safeAdd(O.Of(2))(O.Of(3)))
fmt.Println(safeAdd(O.None[int]())(O.Of(3)))
fmt.Println(safeAdd(O.Of(2))(O.None[int]()))

// Output:
// Some[int](5)
// None[int]
// None[int]
}

func Example_solution10C() {
// startGame :: IO String
startGame := F.Pipe2(
IOO.Of(game),
IOO.Ap[func(Player) string](getFromCache("player1")),
IOO.Ap[string](getFromCache("player2")),
)

startGameTupled := F.Pipe2(
T.MakeTuple2("player1", "player2"),
IOO.TraverseTuple2(getFromCache, getFromCache),
IOO.Map(T.Tupled2(func(a, b Player) string {
return fmt.Sprintf("%s vs %s", a.Name, b.Name)
})),
)

fmt.Println(startGame())
fmt.Println(startGameTupled())

// Output:
// Some[string](Albert vs Theresa)
// Some[string](Albert vs Theresa)
}
89 changes: 89 additions & 0 deletions samples/mostly-adequate/chapter11_transformagain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mostlyadequate

import (
"fmt"
"regexp"

A "github.com/IBM/fp-go/array"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
IOE "github.com/IBM/fp-go/ioeither"
S "github.com/IBM/fp-go/string"
)

func findUserById(id int) IOE.IOEither[error, Chapter08User] {
switch id {
case 1:
return IOE.Of[error](albert08)
case 2:
return IOE.Of[error](gary08)
case 3:
return IOE.Of[error](theresa08)
default:
return IOE.Left[Chapter08User](fmt.Errorf("user %d not found", id))
}
}

func Example_solution11A() {
// eitherToMaybe :: Either b a -> Maybe a
eitherToMaybe := E.ToOption[error, string]

fmt.Println(eitherToMaybe(E.Of[error]("one eyed willy")))
fmt.Println(eitherToMaybe(E.Left[string](fmt.Errorf("some error"))))

// Output:
// Some[string](one eyed willy)
// None[string]
}

func Example_solution11B() {
findByNameId := F.Flow2(
findUserById,
IOE.Map[error](Chapter08User.getName),
)

fmt.Println(findByNameId(1)())
fmt.Println(findByNameId(2)())
fmt.Println(findByNameId(3)())
fmt.Println(findByNameId(4)())

// Output:
// Right[<nil>, string](Albert)
// Right[<nil>, string](Gary)
// Right[<nil>, string](Theresa)
// Left[*errors.errorString, string](user 4 not found)
}

func Example_solution11C() {
// strToList :: String -> [Char
strToList := Split(regexp.MustCompile(``))

// listToStr :: [Char] -> String
listToStr := A.Intercalate(S.Monoid)("")

sortLetters := F.Flow3(
strToList,
A.Sort(S.Ord),
listToStr,
)

fmt.Println(sortLetters("sortme"))

// Output:
// emorst
}

0 comments on commit fb91fd5

Please sign in to comment.