Learning Functional Programming in Go
上QQ阅读APP看书,第一时间看更新

The Contains() method

Now, let's exercise our Contains() method:

func main() {
crv := &Car{"Honda", "CRV"}
is250 := &Car{"Lexus", "IS250"}
highlander := &Car{"Toyota", "Highlander"}
cars := Cars{crv, is250, highlander}
if cars.Contains("Highlander") {
println("Found Highlander")
}
if !cars.Contains("Hummer") {
println("Did NOT find a Hummer")
}
}

The output will be as follows:

Found Highlander
Did NOT find a Hummer

In order to understand how to make the leap from imperative programming to functional programming, let's look at pure functional programming languages and how to implement high-order functions such as Map() that manipulate collections.

With pure functional types, you had a function, f, that takes a cube and returns a heart, as shown in the following diagram:

If you pass f a list of cubes, you could use f to return a list of hearts.

In order to implement this in Go, we can replace the cube with a string and the heart with a bool value:

func Map(f func(v string) bool, vs [] string) []bool {
if len(vs) == 0 {
return nil
}
return append(
[]bool{f(vs[0])},
Map(f, vs[1:])...)
}

First, we define a map of vowels that we later test for a key without retrieving the value, using an underscore in place of the first value:

func main() {
vowels := map[string]bool{
"a": true,
"e": true,
"i": true,
"o": true,
"u": true,
}
isVowel := func(v string) bool { _, ok := vowels[v]; return ok }
letters := []string{"a", "b", "c", "d", "e"}
fmt.Println(Map(isVowel, letters))
}

We define isVowel to be a literal function that takes a string and returns a bool result. We define letters to be a slice of strings (a, b,... e) and then call our Map function, passing our isVowel function and the list of strings to check.

This works well, but the problem is that we would have to rewrite our logic for every data type that we want to use. If we want to check whether a specific rune character exists in a list of runes, we would have to write a new Map function. We would have to be concerned about things such as this: does len() work with runes like it works with strings? If not, we would have to replace this logic. This would include a lot of effort and code, which would perform similar operations and would not be good style.

This is yet another example of why having generics in Go would be a delight.