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:
@@ -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())()
|
||||
}
|
||||
}
|
||||
|
120
samples/presentation/benchmarks/http_test.go
Normal file
120
samples/presentation/benchmarks/http_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
160
samples/presentation/benchmarks/map_test.go
Normal file
160
samples/presentation/benchmarks/map_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
59
samples/presentation/benchmarks/utils.go
Normal file
59
samples/presentation/benchmarks/utils.go
Normal 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)
|
||||
}
|
||||
}
|
@@ -22,6 +22,10 @@ import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
||||
|
||||
func Example_composition_pipe() {
|
||||
|
||||
filter := func(i int) bool {
|
||||
|
Binary file not shown.
Reference in New Issue
Block a user