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) ¶
// 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(PostItem.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 (Solution09C) ¶
// // joinMailingList :: Email -> Either String (IO ())
joinMailingList := F.Flow4(
validateEmail,
IOE.FromEither[error, string],
IOE.Chain(addToMailingList),
IOE.Chain(emailBlast),
)
fmt.Println(joinMailingList("sleepy@grandpa.net")())
fmt.Println(joinMailingList("notanemail")())
Output: Right[<nil>, string](sleepy@grandpa.net) Left[*errors.errorString, string](email notanemail is invalid)
Example (Solution10A) ¶
safeAdd := F.Curry2(func(a, b O.Option[int]) O.Option[int] {
return F.Pipe3(
N.Add[int],
O.Of[func(int) func(int) int],
O.Ap[func(int) int](a),
O.Ap[int](b),
)
})
fmt.Println(safeAdd(O.Of(2))(O.Of(3)))
fmt.Println(safeAdd(O.None[int]())(O.Of(3)))
fmt.Println(safeAdd(O.Of(2))(O.None[int]()))
Output: Some[int](5) None[int] None[int]
Example (Solution10B) ¶
safeAdd := F.Curry2(T.Untupled2(F.Flow2( O.SequenceTuple2[int, int], O.Map(T.Tupled2(N.MonoidSum[int]().Concat)), ))) fmt.Println(safeAdd(O.Of(2))(O.Of(3))) fmt.Println(safeAdd(O.None[int]())(O.Of(3))) fmt.Println(safeAdd(O.Of(2))(O.None[int]()))
Output: Some[int](5) None[int] None[int]
Example (Solution10C) ¶
// startGame :: IO String
startGame := F.Pipe2(
IOO.Of(game),
IOO.Ap[func(Player) string](getFromCache("player1")),
IOO.Ap[string](getFromCache("player2")),
)
startGameTupled := F.Pipe2(
T.MakeTuple2("player1", "player2"),
IOO.TraverseTuple2(getFromCache, getFromCache),
IOO.Map(T.Tupled2(func(a, b Player) string {
return fmt.Sprintf("%s vs %s", a.Name, b.Name)
})),
)
fmt.Println(startGame())
fmt.Println(startGameTupled())
Output: Some[string](Albert vs Theresa) Some[string](Albert vs Theresa)
Example (Solution11A) ¶
// eitherToMaybe :: Either b a -> Maybe a
eitherToMaybe := E.ToOption[error, string]
fmt.Println(eitherToMaybe(E.Of[error]("one eyed willy")))
fmt.Println(eitherToMaybe(E.Left[string](fmt.Errorf("some error"))))
Output: Some[string](one eyed willy) None[string]
Example (Solution11B) ¶
findByNameId := F.Flow2( findUserById, IOE.Map[error](Chapter08User.getName), ) fmt.Println(findByNameId(1)()) fmt.Println(findByNameId(2)()) fmt.Println(findByNameId(3)()) fmt.Println(findByNameId(4)())
Output: Right[<nil>, string](Albert) Right[<nil>, string](Gary) Right[<nil>, string](Theresa) Left[*errors.errorString, string](user 4 not found)
Example (Solution11C) ¶
// strToList :: String -> [Char
strToList := Split(regexp.MustCompile(``))
// listToStr :: [Char] -> String
listToStr := A.Intercalate(S.Monoid)("")
sortLetters := F.Flow3(
strToList,
A.Sort(S.Ord),
listToStr,
)
fmt.Println(sortLetters("sortme"))
Output: emorst
Example (Solution12A) ¶
// getJsons :: Map Route Route -> Task Error (Map Route JSON) getJsons := IOE.TraverseRecord[string](httpGet) fmt.Println(getJsons(routes)())
Output: Right[<nil>, map[string]string](map[/:json for / /about:json for /about])
Example (Solution12B) ¶
// startGame :: [Player] -> [Either Error String]
startGame := F.Flow2(
E.TraverseArray(validatePlayer),
E.MapTo[error, []Player]("Game started"),
)
fmt.Println(startGame(A.From(playerAlbert, playerTheresa)))
fmt.Println(startGame(A.From(playerAlbert, Player{Id: 4})))
Output: Right[<nil>, string](Game started) Left[*errors.errorString, string](player 4 must have a name)
Example (Solution12C) ¶
traverseO := O.Traverse[string](
IOE.Of[error, O.Option[string]],
IOE.Map[error, string, O.Option[string]],
)
// readFirst :: String -> Task Error (Maybe String)
readFirst := F.Pipe2(
readdir,
IOE.Map[error](A.Head[string]),
IOE.Chain(traverseO(readfile("utf-8"))),
)
fmt.Println(readFirst())
Output: Right[<nil>, option.Option[string]](Some[string](content of file1 (utf-8)))
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 (Solution09C)
- Package (Solution10A)
- Package (Solution10B)
- Package (Solution10C)
- Package (Solution11A)
- Package (Solution11B)
- Package (Solution11C)
- Package (Solution12A)
- Package (Solution12B)
- Package (Solution12C)
- 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.