Documentation
¶
Overview ¶
Package mostlyadequate is meant to serve as a go "companion" resource to Professor Frisby's Mostly Adequate Guide.
Example (Application) ¶
package main
import (
"context"
"fmt"
"net/http"
"regexp"
A "github.com/IBM/fp-go/array"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
J "github.com/IBM/fp-go/json"
S "github.com/IBM/fp-go/string"
R "github.com/IBM/fp-go/context/readerioeither"
H "github.com/IBM/fp-go/context/readerioeither/http"
)
type (
FlickrMedia struct {
Link string `json:"m"`
}
FlickrItem struct {
Media FlickrMedia `json:"media"`
}
FlickrFeed struct {
Items []FlickrItem `json:"items"`
}
)
func (f FlickrMedia) getLink() string {
return f.Link
}
func (f FlickrItem) getMedia() FlickrMedia {
return f.Media
}
func (f FlickrFeed) getItems() []FlickrItem {
return f.Items
}
func main() {
// pure
host := "api.flickr.com"
path := "/services/feeds/photos_public.gne"
query := S.Format[string]("?tags=%s&format=json&jsoncallback=?")
url := F.Flow2(
query,
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
sanitizeJsonP := Replace(regexp.MustCompile(`(?s)^\s*\((.*)\)\s*$`))("$1")
// parse jsonP
parseJsonP := F.Flow3(
sanitizeJsonP,
S.ToBytes,
J.Unmarshal[FlickrFeed],
)
// markup
img := S.Format[string]("<img src='%s'/>")
// lenses
mediaUrl := F.Flow2(
FlickrItem.getMedia,
FlickrMedia.getLink,
)
mediaUrls := F.Flow2(
FlickrFeed.getItems,
A.Map(mediaUrl),
)
images := F.Flow2(
mediaUrls,
A.Map(img),
)
client := H.MakeClient(http.DefaultClient)
// func(string) R.ReaderIOEither[[]string]
app := F.Flow5(
url,
H.MakeGetRequest,
H.ReadText(client),
R.ChainEitherK(parseJsonP),
R.Map(images),
)
// R.ReaderIOEither[[]string]
// this is the managed effect that can be called to download and render the images
catImageEffect := app("cats")
// impure, actually executes the effect
catImages := catImageEffect(context.TODO())()
fmt.Println(E.IsRight(catImages))
}
Output: true
Example (Dasherize) ¶
fmt.Println(Dasherize("The world is a vampire"))
Output: the-world-is-a-vampire
Example (Flock) ¶
package main
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 main() {
flockA := MakeFlock(4)
flockB := MakeFlock(2)
flockC := MakeFlock(0)
fmt.Println(flockA.Conjoin(&flockC).Breed(&flockB).Conjoin(flockA.Breed(&flockB)).Seagulls)
}
Output: 32
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
Example (Greeting) ¶
package main
import "fmt"
func Hi(name string) string {
return fmt.Sprintf("Hi %s", name)
}
func Greeting(name string) string {
return Hi(name)
}
func main() {
// functions are first class objects
greet := Hi
fmt.Println(Greeting("times"))
fmt.Println(greet("times"))
}
Output: Hi times Hi times
Example (Pipe) ¶
output := F.Pipe2( "send in the clowns", ToUpper, Exclaim, ) fmt.Println(output)
Output: SEND IN THE CLOWNS!
Example (RenderPage) ¶
package main
import (
"context"
"fmt"
"net/http"
R "github.com/IBM/fp-go/context/readerioeither"
H "github.com/IBM/fp-go/context/readerioeither/http"
F "github.com/IBM/fp-go/function"
)
type PostItem struct {
UserId uint `json:"userId"`
Id uint `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func getTitle(item PostItem) string {
return item.Title
}
func idxToUrl(idx int) string {
return fmt.Sprintf("https://jsonplaceholder.typicode.com/posts/%d", idx+1)
}
func renderString(destinations string) func(string) string {
return func(events string) string {
return fmt.Sprintf("<div>Destinations: [%s], Events: [%s]</div>", destinations, events)
}
}
func main() {
// prepare the http client
client := H.MakeClient(http.DefaultClient)
// get returns the title of the nth item from the REST service
get := F.Flow4(
idxToUrl,
H.MakeGetRequest,
H.ReadJson[PostItem](client),
R.Map(getTitle),
)
res := F.Pipe2(
R.Of(renderString), // start with a function with 2 unresolved arguments
R.Ap[func(string) string](get(1)), // resolve the first argument
R.Ap[string](get(2)), // in parallel resolve the second argument
)
// finally invoke in context and start
fmt.Println(res(context.TODO())())
}
Output: Right[<nil>, string](<div>Destinations: [qui est esse], Events: [ea molestias quasi exercitationem repellat qui ipsa sit aut]</div>)
Example (Shout) ¶
fmt.Println(Shout("send in the clowns"))
Output: SEND IN THE CLOWNS!
Example (Solution04A) ¶
// words :: String -> [String]
words := Split(regexp.MustCompile(` `))
fmt.Println(words("Jingle bells Batman smells"))
Output: [Jingle bells Batman smells]
Example (Solution04B) ¶
// filterQs :: [String] -> [String]
filterQs := A.Filter(Matches(regexp.MustCompile(`q`)))
fmt.Println(filterQs(A.From("quick", "camels", "quarry", "over", "quails")))
Output: [quick quarry quails]
Example (Solution04C) ¶
keepHighest := N.Max[int] // max :: [Number] -> Number max := A.Reduce(keepHighest, math.MinInt) fmt.Println(max(A.From(323, 523, 554, 123, 5234)))
Output: 5234
Example (Solution05A) ¶
IsLastInStock := F.Flow2( A.Last[Car], O.Map(Car.getInStock), ) fmt.Println(IsLastInStock(Cars[0:3])) fmt.Println(IsLastInStock(Cars[3:]))
Output: Some[bool](true) Some[bool](false)
Example (Solution05B) ¶
// averageDollarValue :: [Car] -> Int averageDollarValue := F.Flow2( A.Map(Car.getDollarValue), average, ) fmt.Println(averageDollarValue(Cars))
Output: 790700
Example (Solution05C) ¶
// order by horsepower
ordByHorsepower := ord.Contramap(Car.getHorsepower)(I.Ord)
// fastestCar :: [Car] -> Option[String]
fastestCar := F.Flow3(
A.Sort(ordByHorsepower),
A.Last[Car],
O.Map(F.Flow2(
Car.getName,
S.Format[string]("%s is the fastest"),
)),
)
fmt.Println(fastestCar(Cars))
Output: Some[string](Aston Martin One-77 is the fastest)
Example (Solution08A) ¶
incrF := I.Map(N.Add(1)) fmt.Println(incrF(I.Of(2)))
Output: 3
Example (Solution08B) ¶
// initial :: User -> Option rune initial := F.Flow3( Chapter08User.getName, S.ToRunes, A.Head[rune], ) fmt.Println(initial(albert08))
Output: Some[int32](65)
Example (Solution08C) ¶
// eitherWelcome :: User -> Either String String eitherWelcome := F.Flow2( checkActive, E.Map[error](showWelcome), ) fmt.Println(eitherWelcome(gary08)) fmt.Println(eitherWelcome(theresa08))
Output: Left[*errors.errorString, string](Your account is not active) Right[<nil>, string](Welcome Theresa)
Example (Solution08D) ¶
// // validateName :: User -> Either String ()
validateName := F.Flow3(
Chapter08User.getName,
E.FromPredicate(F.Flow2(
S.Size,
ord.Gt(ord.FromStrictCompare[int]())(3),
), errors.OnSome[string]("Your name %s is larger than 3 characters")),
E.Map[error](F.ToAny[string]),
)
saveAndWelcome := F.Flow2(
save,
IOE.Map[error](showWelcome),
)
register := F.Flow3(
validateUser(validateName),
IOE.FromEither[error, Chapter08User],
IOE.Chain(saveAndWelcome),
)
fmt.Println(validateName(gary08))
fmt.Println(validateName(yi08))
fmt.Println(register(albert08)())
fmt.Println(register(yi08)())
Output: Right[<nil>, string](Gary) Left[*errors.errorString, <nil>](Your name Yi is larger than 3 characters) Right[<nil>, string](Welcome Albert) Left[*errors.errorString, string](Your name Yi is larger than 3 characters)
Example (Solution09A) ¶
// // getStreetName :: User -> Maybe String getStreetName := F.Flow4( Chapter09User.getAddress, Address.getStreet, Street.getName, O.FromPredicate(S.IsNonEmpty), ) fmt.Println(getStreetName(albert09)) fmt.Println(getStreetName(gary09)) fmt.Println(getStreetName(theresa09))
Output: Some[string](Walnut St) None[string] None[string]
Example (Solution09B) ¶
logFilename := F.Flow2( io.Map(path.Base), io.ChainFirst(pureLog), ) fmt.Println(logFilename(getFile)())
Output: ch09.md
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})
Example (Widthdraw) ¶
fmt.Println(getTwenty(MakeAccount(200))) fmt.Println(getTwenty(MakeAccount(10)))
Output: Your balance is $180.00 You're broke!
Index ¶
Examples ¶
- Package (Application)
- Package (Dasherize)
- Package (Flock)
- Package (GetAge)
- Package (Greeting)
- Package (Pipe)
- Package (RenderPage)
- Package (Shout)
- Package (Solution04A)
- Package (Solution04B)
- Package (Solution04C)
- Package (Solution05A)
- Package (Solution05B)
- Package (Solution05C)
- Package (Solution08A)
- Package (Solution08B)
- Package (Solution08C)
- Package (Solution08D)
- Package (Solution09A)
- Package (Solution09B)
- Package (Street)
- Package (Widthdraw)
Constants ¶
This section is empty.
Variables ¶
View Source
var ( Cars = A.From(Car{ Name: "Ferrari FF", Horsepower: 660, DollarValue: 700000, InStock: true, }, Car{ Name: "Spyker C12 Zagato", Horsepower: 650, DollarValue: 648000, InStock: false, }, Car{ Name: "Jaguar XKR-S", Horsepower: 550, DollarValue: 132000, InStock: true, }, Car{ Name: "Audi R8", Horsepower: 525, DollarValue: 114200, InStock: false, }, Car{ Name: "Aston Martin One-77", Horsepower: 750, DollarValue: 1850000, InStock: true, }, Car{ Name: "Pagani Huayra", Horsepower: 700, DollarValue: 1300000, InStock: false, }) )
Functions ¶
This section is empty.
Types ¶
Click to show internal directories.
Click to hide internal directories.