mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
fix: add examples for [Frisby's Mostly Adequate Guide]
This commit is contained in:
23
number/integer/string.go
Normal file
23
number/integer/string.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// 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 integer
|
||||
|
||||
import "strconv"
|
||||
|
||||
var (
|
||||
// ToString converts an integer to a string
|
||||
ToString = strconv.Itoa
|
||||
)
|
14
ord/ord.go
14
ord/ord.go
@@ -131,9 +131,7 @@ func FromStrictCompare[A C.Ordered]() Ord[A] {
|
||||
return MakeOrd(strictCompare[A], strictEq[A])
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is _strictly less than_ another
|
||||
*/
|
||||
// Lt tests whether one value is _strictly less than_ another
|
||||
func Lt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
@@ -142,9 +140,7 @@ func Lt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is less or equal than_ another
|
||||
*/
|
||||
// Leq Tests whether one value is less or equal than_ another
|
||||
func Leq[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
@@ -156,7 +152,7 @@ func Leq[A any](O Ord[A]) func(A) func(A) bool {
|
||||
/**
|
||||
* Test whether one value is _strictly greater than_ another
|
||||
*/
|
||||
func Gt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
func cc[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
return O.Compare(first, second) > 0
|
||||
@@ -164,9 +160,7 @@ func Gt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is greater or equal than_ another
|
||||
*/
|
||||
// Geq tests whether one value is greater or equal than_ another
|
||||
func Geq[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
|
6
samples/mostly-adequate/README.md
Normal file
6
samples/mostly-adequate/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Mostly Adequate: fp-go Companion Guide
|
||||
|
||||
This resource is meant to serve as a go "companion" resource to Professor [Frisby's Mostly Adequate Guide](https://github.com/MostlyAdequate/mostly-adequate-guide).
|
||||
|
||||
It is a port of the [mostly-adequate-fp-ts](https://github.com/ChuckJonas/mostly-adequate-fp-ts/) book.
|
||||
|
47
samples/mostly-adequate/chapter01_test.go
Normal file
47
samples/mostly-adequate/chapter01_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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"
|
||||
|
||||
type Flock struct {
|
||||
Seagulls int
|
||||
}
|
||||
|
||||
func MakeFlock(n int) Flock {
|
||||
return Flock{Seagulls: n}
|
||||
}
|
||||
|
||||
func (f *Flock) Conjoin(other *Flock) *Flock {
|
||||
f.Seagulls += other.Seagulls
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *Flock) Breed(other *Flock) *Flock {
|
||||
f.Seagulls = f.Seagulls * other.Seagulls
|
||||
return f
|
||||
}
|
||||
|
||||
func Example_flock() {
|
||||
|
||||
flockA := MakeFlock(4)
|
||||
flockB := MakeFlock(2)
|
||||
flockC := MakeFlock(0)
|
||||
|
||||
fmt.Println(flockA.Conjoin(&flockC).Breed(&flockB).Conjoin(flockA.Breed(&flockB)).Seagulls)
|
||||
|
||||
// Output: 32
|
||||
}
|
46
samples/mostly-adequate/chapter04_currying_test.go
Normal file
46
samples/mostly-adequate/chapter04_currying_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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 (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
I "github.com/IBM/fp-go/number/integer"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
)
|
||||
|
||||
var (
|
||||
Match = F.Curry2((*regexp.Regexp).FindStringSubmatch)
|
||||
Split = F.Curry2(F.Bind3of3((*regexp.Regexp).Split)(-1))
|
||||
|
||||
Add = N.Add[int]
|
||||
ToString = I.ToString
|
||||
ToLower = strings.ToLower
|
||||
ToUpper = strings.ToUpper
|
||||
Concat = F.Curry2(S.Monoid.Concat)
|
||||
)
|
||||
|
||||
// Replace cannot be generated via [F.Curry3] because the order of parameters does not match our desired curried order
|
||||
func Replace(search *regexp.Regexp) func(replace string) func(s string) string {
|
||||
return func(replace string) func(s string) string {
|
||||
return func(s string) string {
|
||||
return search.ReplaceAllString(s, replace)
|
||||
}
|
||||
}
|
||||
}
|
60
samples/mostly-adequate/chapter05_composing_test.go
Normal file
60
samples/mostly-adequate/chapter05_composing_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
)
|
||||
|
||||
var (
|
||||
Exclaim = S.Format[string]("%s!")
|
||||
Shout = F.Flow2(ToUpper, Exclaim)
|
||||
Dasherize = F.Flow4(
|
||||
Replace(regexp.MustCompile(`\s{2,}`))(" "),
|
||||
Split(regexp.MustCompile(` `)),
|
||||
A.Map(ToLower),
|
||||
A.Intercalate(S.Monoid)("-"),
|
||||
)
|
||||
)
|
||||
|
||||
func Example_shout() {
|
||||
fmt.Println(Shout("send in the clowns"))
|
||||
|
||||
// Output: SEND IN THE CLOWNS!
|
||||
}
|
||||
|
||||
func Example_dasherize() {
|
||||
fmt.Println(Dasherize("The world is a vampire"))
|
||||
|
||||
// Output: the-world-is-a-vampire
|
||||
}
|
||||
|
||||
func Example_pipe() {
|
||||
output := F.Pipe2(
|
||||
"send in the clowns",
|
||||
ToUpper,
|
||||
Exclaim,
|
||||
)
|
||||
|
||||
fmt.Println(output)
|
||||
|
||||
// Output: SEND IN THE CLOWNS!
|
||||
}
|
133
samples/mostly-adequate/chapter08_tupperware_test.go
Normal file
133
samples/mostly-adequate/chapter08_tupperware_test.go
Normal file
@@ -0,0 +1,133 @@
|
||||
// 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"
|
||||
"time"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
"github.com/IBM/fp-go/ord"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
Balance float32
|
||||
}
|
||||
|
||||
func MakeAccount(b float32) Account {
|
||||
return Account{Balance: b}
|
||||
}
|
||||
|
||||
func getBalance(a Account) float32 {
|
||||
return a.Balance
|
||||
}
|
||||
|
||||
var (
|
||||
ordFloat32 = ord.FromStrictCompare[float32]()
|
||||
UpdateLedger = F.Identity[Account]
|
||||
RemainingBalance = F.Flow2(
|
||||
getBalance,
|
||||
S.Format[float32]("Your balance is $%0.2f"),
|
||||
)
|
||||
FinishTransaction = F.Flow2(
|
||||
UpdateLedger,
|
||||
RemainingBalance,
|
||||
)
|
||||
getTwenty = F.Flow2(
|
||||
Withdraw(20),
|
||||
O.Fold(F.Constant("You're broke!"), FinishTransaction),
|
||||
)
|
||||
)
|
||||
|
||||
func Withdraw(amount float32) func(account Account) O.Option[Account] {
|
||||
|
||||
return F.Flow3(
|
||||
getBalance,
|
||||
O.FromPredicate(ord.Geq(ordFloat32)(amount)),
|
||||
O.Map(F.Flow2(
|
||||
N.Add(-amount),
|
||||
MakeAccount,
|
||||
)))
|
||||
}
|
||||
|
||||
type User struct {
|
||||
BirthDate string
|
||||
}
|
||||
|
||||
func getBirthDate(u User) string {
|
||||
return u.BirthDate
|
||||
}
|
||||
|
||||
func MakeUser(d string) User {
|
||||
return User{BirthDate: d}
|
||||
}
|
||||
|
||||
var parseDate = F.Bind1of2(E.Eitherize2(time.Parse))(time.DateOnly)
|
||||
|
||||
func GetAge(now time.Time) func(User) E.Either[error, float64] {
|
||||
return F.Flow3(
|
||||
getBirthDate,
|
||||
parseDate,
|
||||
E.Map[error](F.Flow3(
|
||||
now.Sub,
|
||||
time.Duration.Hours,
|
||||
N.Mul(1/24.0),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
func Example_widthdraw() {
|
||||
fmt.Println(getTwenty(MakeAccount(200)))
|
||||
fmt.Println(getTwenty(MakeAccount(10)))
|
||||
|
||||
// Output:
|
||||
// Your balance is $180.00
|
||||
// You're broke!
|
||||
}
|
||||
|
||||
func Example_getAge() {
|
||||
now, err := time.Parse(time.DateOnly, "2023-09-01")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(GetAge(now)(MakeUser("2005-12-12")))
|
||||
fmt.Println(GetAge(now)(MakeUser("July 4, 2001")))
|
||||
|
||||
fortune := F.Flow3(
|
||||
N.Add(365.0),
|
||||
S.Format[float64]("%0.0f"),
|
||||
Concat("If you survive, you will be "),
|
||||
)
|
||||
|
||||
zoltar := F.Flow3(
|
||||
GetAge(now),
|
||||
E.Map[error](fortune),
|
||||
E.GetOrElse(errors.ToString),
|
||||
)
|
||||
|
||||
fmt.Println(zoltar(MakeUser("2005-12-12")))
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, float64](6472)
|
||||
// Left[*time.ParseError, float64](parsing time "July 4, 2001" as "2006-01-02": cannot parse "July 4, 2001" as "2006")
|
||||
// If you survive, you will be 6837
|
||||
}
|
64
samples/mostly-adequate/chapter09_monadiconions_test.go
Normal file
64
samples/mostly-adequate/chapter09_monadiconions_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// 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"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
type (
|
||||
Street struct {
|
||||
Name string
|
||||
Number int
|
||||
}
|
||||
|
||||
Address struct {
|
||||
Street Street
|
||||
Postcode string
|
||||
}
|
||||
|
||||
AddressBook struct {
|
||||
Addresses []Address
|
||||
}
|
||||
)
|
||||
|
||||
func getAddresses(ab AddressBook) []Address {
|
||||
return ab.Addresses
|
||||
}
|
||||
|
||||
func getStreet(s Address) Street {
|
||||
return s.Street
|
||||
}
|
||||
|
||||
var FirstAddressStreet = F.Flow3(
|
||||
getAddresses,
|
||||
A.Head[Address],
|
||||
O.Map(getStreet),
|
||||
)
|
||||
|
||||
func Example_street() {
|
||||
s := FirstAddressStreet(AddressBook{
|
||||
Addresses: A.From(Address{Street: Street{Name: "Mulburry", Number: 8402}, Postcode: "WC2N"}),
|
||||
})
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// Some[mostlyadequate.Street]({Mulburry 8402})
|
||||
}
|
19
samples/mostly-adequate/doc.go
Normal file
19
samples/mostly-adequate/doc.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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 is meant to serve as a go "companion" resource to Professor [Frisby's Mostly Adequate Guide].
|
||||
//
|
||||
// [Frisby's Mostly Adequate Guide]: https://github.com/MostlyAdequate/mostly-adequate-guide
|
||||
package mostlyadequate
|
Reference in New Issue
Block a user