mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
fix: adjust to some linter findings
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
@@ -32,12 +32,12 @@ import (
|
|||||||
func TestBuilderWithQuery(t *testing.T) {
|
func TestBuilderWithQuery(t *testing.T) {
|
||||||
// add some query
|
// add some query
|
||||||
withLimit := R.WithQueryArg("limit")("10")
|
withLimit := R.WithQueryArg("limit")("10")
|
||||||
withUrl := R.WithUrl("http://www.example.org?a=b")
|
withURL := R.WithUrl("http://www.example.org?a=b")
|
||||||
|
|
||||||
b := F.Pipe2(
|
b := F.Pipe2(
|
||||||
R.Default,
|
R.Default,
|
||||||
withLimit,
|
withLimit,
|
||||||
withUrl,
|
withURL,
|
||||||
)
|
)
|
||||||
|
|
||||||
req := F.Pipe3(
|
req := F.Pipe3(
|
||||||
|
@@ -31,7 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PostItem struct {
|
type PostItem struct {
|
||||||
UserId uint `json:"userId"`
|
UserID uint `json:"userId"`
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
|
@@ -76,7 +76,7 @@ var (
|
|||||||
noBody = O.None[E.Either[error, []byte]]()
|
noBody = O.None[E.Either[error, []byte]]()
|
||||||
noQueryArg = O.None[string]()
|
noQueryArg = O.None[string]()
|
||||||
|
|
||||||
parseUrl = E.Eitherize1(url.Parse)
|
parseURL = E.Eitherize1(url.Parse)
|
||||||
parseQuery = E.Eitherize1(url.ParseQuery)
|
parseQuery = E.Eitherize1(url.ParseQuery)
|
||||||
|
|
||||||
// WithQuery creates a [Endomorphism] for a complete set of query parameters
|
// WithQuery creates a [Endomorphism] for a complete set of query parameters
|
||||||
@@ -153,7 +153,7 @@ func (builder *Builder) GetTargetUrl() E.Either[error, string] {
|
|||||||
return F.Pipe3(
|
return F.Pipe3(
|
||||||
builder,
|
builder,
|
||||||
Url.Get,
|
Url.Get,
|
||||||
parseUrl,
|
parseURL,
|
||||||
E.Chain(F.Flow4(
|
E.Chain(F.Flow4(
|
||||||
T.Replicate2[*url.URL],
|
T.Replicate2[*url.URL],
|
||||||
T.Map2(
|
T.Map2(
|
||||||
|
26
internal/foldable/types.go
Normal file
26
internal/foldable/types.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2024 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 foldable
|
||||||
|
|
||||||
|
import (
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Foldable[A, B, HKTA any] interface {
|
||||||
|
Reduce(func(B, A) B, B) func(HKTA) B
|
||||||
|
ReduceRight(func(B, A) B, B) func(HKTA) B
|
||||||
|
FoldMap(m M.Monoid[B]) func(func(A) B) func(HKTA) B
|
||||||
|
}
|
24
internal/fromeither/types.go
Normal file
24
internal/fromeither/types.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2024 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 fromeither
|
||||||
|
|
||||||
|
import (
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FromEither[E, A, HKTA any] interface {
|
||||||
|
FromEither(ET.Either[E, A]) HKTA
|
||||||
|
}
|
20
internal/fromio/types.go
Normal file
20
internal/fromio/types.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2024 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 fromio
|
||||||
|
|
||||||
|
type FromIO[A, GA ~func() A, HKTA any] interface {
|
||||||
|
FromIO(GA) HKTA
|
||||||
|
}
|
@@ -31,12 +31,12 @@ import (
|
|||||||
func TestBuilderWithQuery(t *testing.T) {
|
func TestBuilderWithQuery(t *testing.T) {
|
||||||
// add some query
|
// add some query
|
||||||
withLimit := R.WithQueryArg("limit")("10")
|
withLimit := R.WithQueryArg("limit")("10")
|
||||||
withUrl := R.WithUrl("http://www.example.org?a=b")
|
withURL := R.WithUrl("http://www.example.org?a=b")
|
||||||
|
|
||||||
b := F.Pipe2(
|
b := F.Pipe2(
|
||||||
R.Default,
|
R.Default,
|
||||||
withLimit,
|
withLimit,
|
||||||
withUrl,
|
withURL,
|
||||||
)
|
)
|
||||||
|
|
||||||
req := F.Pipe3(
|
req := F.Pipe3(
|
||||||
|
@@ -40,7 +40,7 @@ var testLogPolicy = R.CapDelay(
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PostItem struct {
|
type PostItem struct {
|
||||||
UserId uint `json:"userId"`
|
UserID uint `json:"userId"`
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
|
@@ -67,8 +67,8 @@ func isPrimeNumber(num int) bool {
|
|||||||
if num <= 2 {
|
if num <= 2 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
sq_root := int(math.Sqrt(float64(num)))
|
sqRoot := int(math.Sqrt(float64(num)))
|
||||||
for i := 2; i <= sq_root; i++ {
|
for i := 2; i <= sqRoot; i++ {
|
||||||
if num%i == 0 {
|
if num%i == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@@ -33,8 +33,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PostItem struct {
|
type PostItem struct {
|
||||||
UserId uint `json:"userId"`
|
UserID uint `json:"userId"`
|
||||||
Id uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ type CatFact struct {
|
|||||||
Fact string `json:"fact"`
|
Fact string `json:"fact"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func idxToUrl(idx int) string {
|
func idxToURL(idx int) string {
|
||||||
return fmt.Sprintf("https://jsonplaceholder.typicode.com/posts/%d", idx+1)
|
return fmt.Sprintf("https://jsonplaceholder.typicode.com/posts/%d", idx+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ func TestMultipleHttpRequests(t *testing.T) {
|
|||||||
count := 10
|
count := 10
|
||||||
|
|
||||||
data := F.Pipe3(
|
data := F.Pipe3(
|
||||||
A.MakeBy(count, idxToUrl),
|
A.MakeBy(count, idxToURL),
|
||||||
R.TraverseArray(F.Flow3(
|
R.TraverseArray(F.Flow3(
|
||||||
H.MakeGetRequest,
|
H.MakeGetRequest,
|
||||||
readSinglePost,
|
readSinglePost,
|
||||||
@@ -74,7 +74,7 @@ func TestMultipleHttpRequests(t *testing.T) {
|
|||||||
assert.Equal(t, E.Of[error](count), result())
|
assert.Equal(t, E.Of[error](count), result())
|
||||||
}
|
}
|
||||||
|
|
||||||
func heterogeneousHttpRequests() R.ReaderIOEither[T.Tuple2[PostItem, CatFact]] {
|
func heterogeneousHTTPRequests() R.ReaderIOEither[T.Tuple2[PostItem, CatFact]] {
|
||||||
// prepare the http client
|
// prepare the http client
|
||||||
client := H.MakeClient(HTTP.DefaultClient)
|
client := H.MakeClient(HTTP.DefaultClient)
|
||||||
// readSinglePost sends a GET request and parses the response as [PostItem]
|
// readSinglePost sends a GET request and parses the response as [PostItem]
|
||||||
@@ -97,7 +97,7 @@ func heterogeneousHttpRequests() R.ReaderIOEither[T.Tuple2[PostItem, CatFact]] {
|
|||||||
// TestHeterogeneousHttpRequests shows how to execute multiple HTTP requests in parallel when
|
// TestHeterogeneousHttpRequests 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
|
// the response structure of these requests is different. We use [R.TraverseTuple2] to account for the different types
|
||||||
func TestHeterogeneousHttpRequests(t *testing.T) {
|
func TestHeterogeneousHttpRequests(t *testing.T) {
|
||||||
data := heterogeneousHttpRequests()
|
data := heterogeneousHTTPRequests()
|
||||||
|
|
||||||
result := data(context.Background())
|
result := data(context.Background())
|
||||||
|
|
||||||
@@ -108,6 +108,6 @@ func TestHeterogeneousHttpRequests(t *testing.T) {
|
|||||||
// the response structure of these requests is different. We use [R.TraverseTuple2] to account for the different types
|
// the response structure of these requests is different. We use [R.TraverseTuple2] to account for the different types
|
||||||
func BenchmarkHeterogeneousHttpRequests(b *testing.B) {
|
func BenchmarkHeterogeneousHttpRequests(b *testing.B) {
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
heterogeneousHttpRequests()(context.Background())()
|
heterogeneousHTTPRequests()(context.Background())()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -67,26 +67,26 @@ func Example_application() {
|
|||||||
S.Format[string](fmt.Sprintf("https://%s%s%%s", host, path)),
|
S.Format[string](fmt.Sprintf("https://%s%s%%s", host, path)),
|
||||||
)
|
)
|
||||||
// flick returns jsonP, we extract the JSON body, this is handled by jquery in the original code
|
// flick returns jsonP, we extract the JSON body, this is handled by jquery in the original code
|
||||||
sanitizeJsonP := Replace(regexp.MustCompile(`(?s)^\s*\((.*)\)\s*$`))("$1")
|
sanitizeJSONP := Replace(regexp.MustCompile(`(?s)^\s*\((.*)\)\s*$`))("$1")
|
||||||
// parse jsonP
|
// parse jsonP
|
||||||
parseJsonP := F.Flow3(
|
parseJSONP := F.Flow3(
|
||||||
sanitizeJsonP,
|
sanitizeJSONP,
|
||||||
S.ToBytes,
|
S.ToBytes,
|
||||||
J.Unmarshal[FlickrFeed],
|
J.Unmarshal[FlickrFeed],
|
||||||
)
|
)
|
||||||
// markup
|
// markup
|
||||||
img := S.Format[string]("<img src='%s'/>")
|
img := S.Format[string]("<img src='%s'/>")
|
||||||
// lenses
|
// lenses
|
||||||
mediaUrl := F.Flow2(
|
mediaURL := F.Flow2(
|
||||||
FlickrItem.getMedia,
|
FlickrItem.getMedia,
|
||||||
FlickrMedia.getLink,
|
FlickrMedia.getLink,
|
||||||
)
|
)
|
||||||
mediaUrls := F.Flow2(
|
mediaURLs := F.Flow2(
|
||||||
FlickrFeed.getItems,
|
FlickrFeed.getItems,
|
||||||
A.Map(mediaUrl),
|
A.Map(mediaURL),
|
||||||
)
|
)
|
||||||
images := F.Flow2(
|
images := F.Flow2(
|
||||||
mediaUrls,
|
mediaURLs,
|
||||||
A.Map(img),
|
A.Map(img),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ func Example_application() {
|
|||||||
url,
|
url,
|
||||||
H.MakeGetRequest,
|
H.MakeGetRequest,
|
||||||
H.ReadText(client),
|
H.ReadText(client),
|
||||||
R.ChainEitherK(parseJsonP),
|
R.ChainEitherK(parseJSONP),
|
||||||
R.Map(images),
|
R.Map(images),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -32,7 +32,7 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
PostItem struct {
|
PostItem struct {
|
||||||
UserId uint `json:"userId"`
|
UserID uint `json:"userId"`
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
@@ -77,7 +77,7 @@ func (player Player) getName() string {
|
|||||||
return player.Name
|
return player.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player Player) getId() int {
|
func (player Player) getID() int {
|
||||||
return player.Id
|
return player.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ func (item PostItem) getTitle() string {
|
|||||||
return item.Title
|
return item.Title
|
||||||
}
|
}
|
||||||
|
|
||||||
func idxToUrl(idx int) string {
|
func idxToURL(idx int) string {
|
||||||
return fmt.Sprintf("https://jsonplaceholder.typicode.com/posts/%d", idx+1)
|
return fmt.Sprintf("https://jsonplaceholder.typicode.com/posts/%d", idx+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ func Example_renderPage() {
|
|||||||
|
|
||||||
// get returns the title of the nth item from the REST service
|
// get returns the title of the nth item from the REST service
|
||||||
get := F.Flow4(
|
get := F.Flow4(
|
||||||
idxToUrl,
|
idxToURL,
|
||||||
H.MakeGetRequest,
|
H.MakeGetRequest,
|
||||||
H.ReadJson[PostItem](client),
|
H.ReadJson[PostItem](client),
|
||||||
R.Map(PostItem.getTitle),
|
R.Map(PostItem.getTitle),
|
||||||
|
@@ -26,7 +26,7 @@ import (
|
|||||||
S "github.com/IBM/fp-go/string"
|
S "github.com/IBM/fp-go/string"
|
||||||
)
|
)
|
||||||
|
|
||||||
func findUserById(id int) IOE.IOEither[error, Chapter08User] {
|
func findUserByID(id int) IOE.IOEither[error, Chapter08User] {
|
||||||
switch id {
|
switch id {
|
||||||
case 1:
|
case 1:
|
||||||
return IOE.Of[error](albert08)
|
return IOE.Of[error](albert08)
|
||||||
@@ -52,15 +52,15 @@ func Example_solution11A() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Example_solution11B() {
|
func Example_solution11B() {
|
||||||
findByNameId := F.Flow2(
|
findByNameID := F.Flow2(
|
||||||
findUserById,
|
findUserByID,
|
||||||
IOE.Map[error](Chapter08User.getName),
|
IOE.Map[error](Chapter08User.getName),
|
||||||
)
|
)
|
||||||
|
|
||||||
fmt.Println(findByNameId(1)())
|
fmt.Println(findByNameID(1)())
|
||||||
fmt.Println(findByNameId(2)())
|
fmt.Println(findByNameID(2)())
|
||||||
fmt.Println(findByNameId(3)())
|
fmt.Println(findByNameID(3)())
|
||||||
fmt.Println(findByNameId(4)())
|
fmt.Println(findByNameID(4)())
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Right[<nil>, string](Albert)
|
// Right[<nil>, string](Albert)
|
||||||
|
@@ -42,7 +42,7 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validate :: Player -> Either error Player
|
// validate :: Player -> Either error Player
|
||||||
validatePlayer = E.FromPredicate(P.ContraMap(Player.getName)(S.IsNonEmpty), F.Flow2(Player.getId, errors.OnSome[int]("player %d must have a name")))
|
validatePlayer = E.FromPredicate(P.ContraMap(Player.getName)(S.IsNonEmpty), F.Flow2(Player.getID, errors.OnSome[int]("player %d must have a name")))
|
||||||
|
|
||||||
// readfile :: String -> String -> Task Error String
|
// readfile :: String -> String -> Task Error String
|
||||||
readfile = F.Curry2(func(encoding, file string) IOE.IOEither[error, string] {
|
readfile = F.Curry2(func(encoding, file string) IOE.IOEither[error, string] {
|
||||||
|
@@ -31,7 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PostItem struct {
|
type PostItem struct {
|
||||||
UserId uint `json:"userId"`
|
UserID uint `json:"userId"`
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
@@ -41,7 +41,7 @@ type CatFact struct {
|
|||||||
Fact string `json:"fact"`
|
Fact string `json:"fact"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func heterogeneousHttpRequests(count int) R.ReaderIOEither[[]T.Tuple2[PostItem, CatFact]] {
|
func heterogeneousHTTPRequests(count int) R.ReaderIOEither[[]T.Tuple2[PostItem, CatFact]] {
|
||||||
// prepare the http client
|
// prepare the http client
|
||||||
client := H.MakeClient(HTTP.DefaultClient)
|
client := H.MakeClient(HTTP.DefaultClient)
|
||||||
// readSinglePost sends a GET request and parses the response as [PostItem]
|
// readSinglePost sends a GET request and parses the response as [PostItem]
|
||||||
@@ -64,7 +64,7 @@ func heterogeneousHttpRequests(count int) R.ReaderIOEither[[]T.Tuple2[PostItem,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func heterogeneousHttpRequestsIdiomatic(count int) ([]T.Tuple2[PostItem, CatFact], error) {
|
func heterogeneousHTTPRequestsIdiomatic(count int) ([]T.Tuple2[PostItem, CatFact], error) {
|
||||||
// prepare the http client
|
// prepare the http client
|
||||||
var result []T.Tuple2[PostItem, CatFact]
|
var result []T.Tuple2[PostItem, CatFact]
|
||||||
|
|
||||||
@@ -109,13 +109,13 @@ func BenchmarkHeterogeneousHttpRequests(b *testing.B) {
|
|||||||
|
|
||||||
b.Run("functional", func(b *testing.B) {
|
b.Run("functional", func(b *testing.B) {
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
benchResults = heterogeneousHttpRequests(count)(context.Background())()
|
benchResults = heterogeneousHTTPRequests(count)(context.Background())()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
b.Run("idiomatic", func(b *testing.B) {
|
b.Run("idiomatic", func(b *testing.B) {
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
benchResults, _ = heterogeneousHttpRequestsIdiomatic(count)
|
benchResults, _ = heterogeneousHTTPRequestsIdiomatic(count)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user