1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-08-10 22:31:32 +02:00

fix: add presentation and samples

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2023-10-27 13:03:17 +02:00
parent 347c66a732
commit 904af10b09
6 changed files with 346 additions and 2 deletions

View File

@@ -107,6 +107,7 @@ func TestHeterogeneousHttpRequests(t *testing.T) {
// BenchmarkHeterogeneousHttpRequests shows how to execute multiple HTTP requests in parallel when
// the response structure of these requests is different. We use [R.TraverseTuple2] to account for the different types
func BenchmarkHeterogeneousHttpRequests(b *testing.B) {
heterogeneousHttpRequests()(context.Background())
for n := 0; n < b.N; n++ {
heterogeneousHttpRequests()(context.Background())()
}
}

View File

@@ -0,0 +1,120 @@
// 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 benchmarks
import (
"context"
"encoding/json"
"io"
"testing"
HTTP "net/http"
A "github.com/IBM/fp-go/array"
R "github.com/IBM/fp-go/context/readerioeither"
H "github.com/IBM/fp-go/context/readerioeither/http"
F "github.com/IBM/fp-go/function"
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 CatFact struct {
Fact string `json:"fact"`
}
func heterogeneousHttpRequests(count int) R.ReaderIOEither[[]T.Tuple2[PostItem, CatFact]] {
// prepare the http client
client := H.MakeClient(HTTP.DefaultClient)
// readSinglePost sends a GET request and parses the response as [PostItem]
readSinglePost := H.ReadJson[PostItem](client)
// readSingleCatFact sends a GET request and parses the response as [CatFact]
readSingleCatFact := H.ReadJson[CatFact](client)
single := F.Pipe2(
T.MakeTuple2("https://jsonplaceholder.typicode.com/posts/1", "https://catfact.ninja/fact"),
T.Map2(H.MakeGetRequest, H.MakeGetRequest),
R.TraverseTuple2(
readSinglePost,
readSingleCatFact,
),
)
return F.Pipe1(
A.Replicate(count, single),
R.SequenceArray[T.Tuple2[PostItem, CatFact]],
)
}
func heterogeneousHttpRequestsIdiomatic(count int) ([]T.Tuple2[PostItem, CatFact], error) {
// prepare the http client
var result []T.Tuple2[PostItem, CatFact]
for i := 0; i < count; i++ {
resp, err := HTTP.Get("https://jsonplaceholder.typicode.com/posts/1")
if err != nil {
return nil, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var item PostItem
err = json.Unmarshal(body, &item)
if err != nil {
return nil, err
}
resp, err = HTTP.Get("https://catfact.ninja/fact")
if err != nil {
return nil, err
}
body, err = io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var fact CatFact
err = json.Unmarshal(body, &item)
if err != nil {
return nil, err
}
result = append(result, T.MakeTuple2(item, fact))
}
return result, nil
}
// BenchmarkHeterogeneousHttpRequests shows how to execute multiple HTTP requests in parallel when
// the response structure of these requests is different. We use [R.TraverseTuple2] to account for the different types
func BenchmarkHeterogeneousHttpRequests(b *testing.B) {
count := 100
b.Run("functional", func(b *testing.B) {
for n := 0; n < b.N; n++ {
heterogeneousHttpRequests(count)(context.Background())()
}
})
b.Run("idiomatic", func(b *testing.B) {
for n := 0; n < b.N; n++ {
heterogeneousHttpRequestsIdiomatic(count)
}
})
}

View File

@@ -0,0 +1,160 @@
// 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 benchmarks
import (
"math/big"
"strings"
"testing"
A "github.com/IBM/fp-go/array"
F "github.com/IBM/fp-go/function"
N "github.com/IBM/fp-go/number"
O "github.com/IBM/fp-go/option"
)
var (
createStringSet = createRandom(createRandomString(256))(256)
createIntDataSet = createRandom(randInt(10000))(256)
)
func BenchmarkMap(b *testing.B) {
data := createStringSet()
b.Run("functional", func(b *testing.B) {
for n := 0; n < b.N; n++ {
F.Pipe1(
data,
A.Map(strings.ToUpper),
)
}
})
b.Run("idiomatic", func(b *testing.B) {
for n := 0; n < b.N; n++ {
var result = make([]string, 0, len(data))
for _, value := range data {
result = append(result, strings.ToUpper(value))
}
}
})
}
func isEven(data int) bool {
return data%2 == 0
}
func isPrime(data int) bool {
return big.NewInt(int64(data)).ProbablyPrime(0)
}
func BenchmarkMapThenFilter(b *testing.B) {
data := createIntDataSet()
b.Run("functional isPrime", func(b *testing.B) {
for n := 0; n < b.N; n++ {
F.Pipe2(
data,
A.Filter(isPrime),
A.Map(N.Div[int](2)),
)
}
})
b.Run("idiomatic isPrime", func(b *testing.B) {
for n := 0; n < b.N; n++ {
var result []int
for _, value := range data {
if isPrime(value) {
result = append(result, value/2)
}
}
}
})
b.Run("functional isEven", func(b *testing.B) {
for n := 0; n < b.N; n++ {
F.Pipe2(
data,
A.Filter(isEven),
A.Map(N.Div[int](2)),
)
}
})
b.Run("idiomatic isEven", func(b *testing.B) {
for n := 0; n < b.N; n++ {
var result []int
for _, value := range data {
if isEven(value) {
result = append(result, value/2)
}
}
}
})
}
func BenchmarkFilterMap(b *testing.B) {
data := createIntDataSet()
b.Run("functional isPrime", func(b *testing.B) {
for n := 0; n < b.N; n++ {
F.Pipe1(
data,
A.FilterMap(F.Flow2(
O.FromPredicate(isPrime),
O.Map(N.Div[int](2)),
)),
)
}
})
b.Run("idiomatic isPrime", func(b *testing.B) {
for n := 0; n < b.N; n++ {
var result []int
for _, value := range data {
if isPrime(value) {
result = append(result, value/2)
}
}
}
})
b.Run("functional isEven", func(b *testing.B) {
for n := 0; n < b.N; n++ {
F.Pipe1(
data,
A.FilterMap(F.Flow2(
O.FromPredicate(isEven),
O.Map(N.Div[int](2)),
)),
)
}
})
b.Run("idiomatic isEven", func(b *testing.B) {
for n := 0; n < b.N; n++ {
var result []int
for _, value := range data {
if isEven(value) {
result = append(result, value/2)
}
}
}
})
}

View File

@@ -0,0 +1,59 @@
// 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 benchmarks
import (
"math/rand"
"time"
A "github.com/IBM/fp-go/array"
B "github.com/IBM/fp-go/bytes"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
)
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var (
seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
randChar = F.Pipe2(
len(charset),
randInt,
IO.Map(charAt),
)
createRandomString = F.Flow3(
F.Bind2of2(A.Replicate[IO.IO[byte]])(randChar),
IO.SequenceArray[byte],
IO.Map(B.ToString),
)
)
func createRandom[T any](single IO.IO[T]) func(size int) IO.IO[[]T] {
return F.Flow2(
F.Bind2of2(A.Replicate[IO.IO[T]])(single),
IO.SequenceArray[T],
)
}
func charAt(idx int) byte {
return charset[idx]
}
func randInt(count int) IO.IO[int] {
return func() int {
return seededRand.Intn(count)
}
}

View File

@@ -22,6 +22,10 @@ import (
F "github.com/IBM/fp-go/function"
)
func main() {
}
func Example_composition_pipe() {
filter := func(i int) bool {