Given that Go has slices and closures, it seems entirely natural for it
to have map, filter and reduce (or collect, filter, inject or fold --
choose your favourite name for the functions). Given the type
interface{} and reflection it is clearly possible to write these -- and
I am hoping that someone has already done that, that they are in the
standard library and I have just missed them.
I have spotted Apply in the itertools package and various Map functions
in gotgo, but I think having a package hof containing these higher order
functions and a partial application function in would be a great benefit
for Go.
I appreciate that there are going to be arguments about efficiency and
performance using reflection . . .
--
Russel.
=============================================================================
Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel...@ekiga.net
41 Buckmaster Road m: +44 7770 465 077 xmpp: rus...@russel.org.uk
London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
I think the main reason they aren't in the standard library yet is the
lack of generics.
interface{} can do it, but it's not very nice. The runtime type check
and the overhead of reflection isn't great. This is the same reason
there aren't a lot of container structures there.
It's best not to have them in the standard library until this issue is
resolved, otherwise people will start using it and lots of code will
get broken when it eventually gets changed.
- jessta
--
=====================
http://jessta.id.au
On Sun, 2010-06-27 at 14:45 -0700, peterGo wrote:
> Russel,
>
> This may not be hard to do. For example, I wrote a prototype reduce
> and ran some tests as a result of a discussion on general min and max
> functions. The number sequence was described by a variable number of
> interface{} arguments, a slice of interface{} arguments, or, the
> primitive form, a pair of interface{} arguments. The functions were
> greaterthan() and lessthan(). The cost of the type assertion in the
> function was the major expense.
Can you point me at the code you wrote -- any examples of using the Go
reflection system are very useful. Whilst I am comfortable with the
meta-object protocol systems in Groovy and (the restricted form) in
Python, and the reflection system of Java, the Go model still hasn't
quite jelled -- I am having difficulty getting the size of the passed
slice so as to make a new slice of the same size but of the type of the
return value of the function for my map function. This maybe because I
am not trying hard enough.
I guess what is really important is to agree the signature of map,
filter and reduce, so everyone looking at this in any way is working
towards the same goal. I was thinking (in pseudocode):
map ( func(X)Y , slice<X> ) slice<Y>
filter ( func(X)bool , slice<X> ) slice<X>
reduce ( func(X,Y)Y , Y , slice<X> ) Y
but I am not committed to this if there is another, more widely
acceptable choice.
--
Russel.
=============================================================================
Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel...@ekiga.net
The lack of generics isn't really a barrier as long as there is a
reflection system that enables checking consistency of the types at
runtime. Generics move things from runtime to compile time and so are
beneficial -- assuming you don't do what Java did which is type erasure.
Yuk.
> interface{} can do it, but it's not very nice. The runtime type check
> and the overhead of reflection isn't great. This is the same reason
> there aren't a lot of container structures there.
It's good to know the overhead is not huge.
Generics is just a way of enforcing at compile time type consistency for
containers where the types have to be consistent. Containers don't
necessarily have to be homogeneous -- though I agree it does help.
> It's best not to have them in the standard library until this issue is
> resolved, otherwise people will start using it and lots of code will
> get broken when it eventually gets changed.
I hope Go isn't already at the stage of having to obsess about backward
compatibility, it is supposed to be in an experimental stage. Clearly
it is better to avoid API breakages, but isn't having the right language
better than causing a little bit of pain along the way.
Historically the JVM tried to avoid all breaking changes, hence type
erasure, but then they went and made breaking changes anyway for
annotations -- which means they could have made a breaking change for
generics and avoided type erasure, which is what they should have done.
It's not about obsessing about backwards compatibility. The Go Devs
seem to love breaking things.
It's knowing that you definitely will have to re-write the code and
that the eventually change will definitely break everything that uses
it. So why write the code when you can just wait until you can
actually write it properly.
Rewriting is definitely a pain, I agree. However, not having a single,
central, quality set of data structures that are actively maintained by
people interested in that sort of stuff that everyone can work with,
everyone has to write their own. Or perhaps chooses a different
programming language?
I guess the converse argument is that very few people properly use all
the weird and wonderful data structures in C++ and Java, and Python
users seem happy with sequence and dictionary.
For me the generic data structures issue is actually much less of a
problem than not having map, filter and reduce, either as functions or
as comprehensions.
> I guess what is really important is to agree the signature of map,
> filter and reduce, so everyone looking at this in any way is working
> towards the same goal. I was thinking (in pseudocode):
>
> map ( func(X)Y , slice<X> ) slice<Y>
> filter ( func(X)bool , slice<X> ) slice<X>
> reduce ( func(X,Y)Y , Y , slice<X> ) Y
>
> but I am not committed to this if there is another, more widely
> acceptable choice.
The current reflection support does not permit creating a new type
defined in terms of other types. It only supports creating new values
of existing types. This makes it difficult to write your suggested map
function, as there is no way to create a value of type slice<Y>.
Ian