1
0
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:
Dr. Carsten Leue
2023-09-01 17:31:47 +02:00
parent ce66cf2295
commit fb3b1f115c
9 changed files with 402 additions and 10 deletions

23
number/integer/string.go Normal file
View 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
)

View File

@@ -131,9 +131,7 @@ func FromStrictCompare[A C.Ordered]() Ord[A] {
return MakeOrd(strictCompare[A], strictEq[A]) return MakeOrd(strictCompare[A], strictEq[A])
} }
/** // Lt tests whether one value is _strictly less than_ another
* Test whether one value is _strictly less than_ another
*/
func Lt[A any](O Ord[A]) func(A) func(A) bool { func Lt[A any](O Ord[A]) func(A) func(A) bool {
return func(second A) func(A) bool { return func(second A) func(A) bool {
return func(first A) bool { return func(first A) bool {
@@ -142,9 +140,7 @@ func Lt[A any](O Ord[A]) func(A) func(A) bool {
} }
} }
/** // Leq Tests whether one value is less or equal than_ another
* Test whether one value is less or equal than_ another
*/
func Leq[A any](O Ord[A]) func(A) func(A) bool { func Leq[A any](O Ord[A]) func(A) func(A) bool {
return func(second A) func(A) bool { return func(second A) func(A) bool {
return func(first 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 * 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(second A) func(A) bool {
return func(first A) bool { return func(first A) bool {
return O.Compare(first, second) > 0 return O.Compare(first, second) > 0
@@ -164,9 +160,7 @@ func Gt[A any](O Ord[A]) func(A) func(A) bool {
} }
} }
/** // Geq tests whether one value is greater or equal than_ another
* Test whether one value is greater or equal than_ another
*/
func Geq[A any](O Ord[A]) func(A) func(A) bool { func Geq[A any](O Ord[A]) func(A) func(A) bool {
return func(second A) func(A) bool { return func(second A) func(A) bool {
return func(first A) bool { return func(first A) bool {

View 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.

View 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
}

View 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)
}
}
}

View 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!
}

View 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
}

View 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})
}

View 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