4 ms·
Go's lack of type parametrisation makes many higher order functions really awkward. I'm no expert on Go, but below is my attempt at writing a generic Map funct
by gnuvince 14y ago
Go's lack of type parametrisation makes many higher order functions really awkward. I'm no expert on Go, but below is my attempt at writing a generic Map function. As you can see, the code of the Map function itself isn't so bad (though there's a lot of noise in the declaration). Using that function however is really annoying, as you need to convert from the slice you have ([]string, []int, etc.) to an empty interface slice, and in the function you give to Map, you need to dispatch on the element's dynamic type. I think this is why Go people prefer to just use for loops and not do the whole higher-order combinators stuff.
package main
import (
"fmt"
)
func Map(fn func(interface{}) interface{}, xs []interface{}) []interface{} {
res := make([]interface{}, len(xs))
for i, x := range(xs) {
res[i] = fn(x)
}
return res
}
func main() {
words := []string{"foo", "bar", "baz"};
// First we need to create a version of words that has the []interface{} type.
interface_words := make([]interface{}, len(words))
for i, w := range(words) {
interface_words[i] = interface{}(w)
}
fmt.Printf("%v\n", Map(
func(x interface{}) interface{} {
switch s := x.(type) {
case string:
return s + "!!"
}
return interface{}(0) // Need to please the compiler.
}, interface_words))
}
- methehack 14y agoThank you for your answer. If you're right and this is the Go way to do it (and I have no reason to doubt you), it's exactly what I was afraid of. I can see why for loops would just read better. Feels like a step in the wrong direction though -- at least for me.
- gnuvince 14y agoGo's lack of parametric polymorphism is an abundant source of Internet debate; proponents of Go say that it keeps the language simpler and find that they don't miss it in practice. I won't get into that debate (it's too late anyway), but I'll say that if you are writing an application, that kind of polymorphism might not be as useful since you can know all the types of your application. Why bother making a generic function if you know you are only ever going to use it with strings? When you are writing libraries however, you don't have this sort of freedom.
- f2f 14y agoHere's a more idiomatic go version: http://play.golang.org/p/oH850AdLuQ http://play.golang.org/p/oH850AdLuQ what you don't realize (apart from the fact that go doesn't terminate lines with semicolons since 2009) is that you don't need to create a copy that's typed []interface{} because []X already satisfies interface{} and you can use reflection to handle it. if a seasoned Go programmer wanted to write a somewhat generic map function they'd do something similar to this: http://play.golang.org/p/qM8sBNcdwY http://play.golang.org/p/qM8sBNcdwY It doesn't look pretty and you're right, most go programmers don't have to write code like this. It is much more common to define a common interface for something that's map-able and expect callers to implement that. examples in sort.Interface.
- gnuvince 14y agoIn your more idiomatic version, you actually went ahead and changed the declaration of words to be []interface{}, but you may not be in control of the type of words (for instance if it's the return value of a function). This is why I did the explicit conversion. As for the reflection, it's pretty ugly. Also, what about semi-colons?
- f2f 14y agoi understand why you did the explicit conversion, the idea i was trying to relay is why i undid it... nevermind the semicolons, 'twas a joke :)