Tag Archives: functional

Add Map, Reduce, and Filter to Groovy with an Extension Module

Having just read Michał Mally’s blog that was posted on Google+,
I was intrigued with two benefits listed in the blog:

  • The idea of being able to augment Groovy with changes that would behave as “if they were a part of original GDK”
  • support from your IDE like code completion shall be available out-of-the-box

In order to get my head around how Extension modules worked, I used the following as references
Creating an extension module
Groovy Goodness: Adding Extra Methods Using Extension Modules
Groovy Extension Modules

Cédric Champeau had this to say after I asked about the benefits of Extension Modules over using MetaClass/Expando/Category

@Juan: extension modules are automatically loaded and made available globally. You don’t have to bother with metaclasses (and potential issues with external changes). As well, categories are lexically scoped, although extension modules are global (meaning that they can be used anywhere in the code as long as the extension module is found on classpath).

Last but not least, extension modules are compatible with type checking and static compilation 🙂

To solidify my new understanding of Groovy’s Extension Modules, I decided that I needed to write some code. The example I came up with was to have the functional names (map, reduce, filter ) that I had come familiar with in using Clojure added to Groovy. These “extended methods” are using Groovy’s built-in collect, inject, and grep under the hood.

Source code can be found here

Here is the code for the new aliases found in the FuncProgUtilExtension.groovy class

package com.javazquez;

public class FuncProgUtilExtension {
    public static Collection filter(Collection self, Closure clozure) {
	   return self.grep(clozure)
   }
   public static Collection map(Collection self, Closure clozure) {
	   return self.collect(clozure)
   }
   public static Object reduce(Collection self, Closure clozure) {
	   return self.inject(clozure)
   }
   public static Object reduce(Collection self, String operator) {
	   switch(operator){
		   case '+' :
		      self.inject({acc, val -> acc + val})
			  break
		   case '-' :
			   self.inject({acc, val -> acc - val})
			   break
		   case'*' :
			   self.inject({acc, val -> acc * val})
			   break
		   case '/':
		   	   self.inject({acc, val -> acc / val})
			   break
		   case'**':
		   	   self.inject({acc, val -> Math.pow(acc, val)})
			   break
		   default:
			   throw new IllegalArgumentException()
			   break
	   }
   }
}

In a file named ‘org.codehaus.groovy.runtime.ExtensionModule’ located in ‘src/main/resources/META-INF/services/’

I have the following

moduleName=JavazquezFuncProgTest
moduleVersion=1.0
extensionClasses=com.javazquez.FuncProgUtilExtention

Using spock, I wrote the following tests :

package com.javazquez

import spock.lang.Specification

class FuncProgUtilSpec extends Specification{

	def "test map"(){
		expect:
			[ 1 ,2 ,3 ,4].map{it*2} == 	[ 1 ,2 ,3 ,4].collect{ it*2 } 	
	}	
	def "test reduce "(){
		expect:
			[ 1 ,2 ,3].reduce('*') == 6
			[ 1 ,2 ,3,4].reduce('+') == 10
			[ '1' ,'2' ,'3','4'].reduce('+') == '1234'
			[ 1 ,2 ,3].reduce('-') == -4
			[ 2, 2 ,2].reduce('**') == 16
			[ 1 ,2 ,3].reduce({acc, val -> acc + val}) ==[ 1 ,2 ,3].inject { acc, val -> acc + val}
	}
	def "test invalid argument"(){
	 	when:
	 		[ 1 ,2 ,3,4].reduce('%')
		then:
			thrown(IllegalArgumentException)
	}
	def "test filter"(){
		expect:
			[1,2,3,4,5,6,7,8,9].filter { it % 2 ==0 } == [2,4,6,8]
			[1,2,3,4,5,6,7,8,9].filter { it > 2 } == [3,4,5,6,7,8,9]
			"Juan Vazquez".toList().filter { it ==~ /[aeiou]/} == ['u','a','a','u','e']
	}
}

My biggest obstacle was getting the directory structure correct. It is amazing how little code was required to accomplish my goal. I hope my example project and listed references will help in your understanding of this powerful feature. My next step with this project going to be to make evaluation lazy.

(def Bonjour-Clojure “Welcome to functional programming”)

After the briefest of introductions to functional programming in college(a la Lisp) and dabbling with Scala, I took the functional plunge and started using Clojure recently. At this point, I have only written a couple of small programs and haven’t formed much of an opinion on where it stacks against my current favorite language at the moment(Groovy). This post will follow my usual getting started with a language snippets. I plan to write more entries as I get more familiar with the language. On to the code!


;binding
user=> (def Bonjour-Clojure “Welcome to functional programming”)
#’user/Bonjour-Clojure
user=> Bonjour-Clojure
“Welcome to functional programming”

;items in a list can be seperated via a comma or white space..
user=> (= [ 1 2 3] [1,2,3])
true

;count the number of consonants in a string
(defn count-consonants [string] (count ( re-seq #”[^aeiouAEIOU\s]” string )))
user=> (count-consonants “writing code is fun”)
10

;count the number of vowels in a string
(defn count-vowels [string] (count ( re-seq #”[aeiouAEIOU\s]” string )))
user=> (count-vowels “lukaskiewicz”)
5

;read a file into a list.. any suggestions on other ways are welcome 🙂
;usage (file-lines “string_path_to_file”) or to read a webpage ((file-lines “http://javazquez.com”)
(defn file-lines [file] (with-open [rdr (clojure.java.io/reader file)] ( set ( line-seq rdr))))

;view objects class
user=>(class “Im a string”)
java.lang.String

;length of string
user=>(count “I am 18 chars long”)
18

user=>(range 1 9)
(1 2 3 4 5 6 7 8 )

;repeat a digit
user=>(repeat 4 3)
(3 3 3 3)

;list comprehension
user=>(for [fruit [“apple” “orange” “grape”] ] (str fruit))
(“apple” “orange” “grape”)

;use map to create a new list… #() is a shortcut for an anonymous
user=>(map #(* 2 %1) [1 2 3 4])
(2 4 6 8 )

; also an anonymous function
user=> (map (fn [item](* 2 item)) [1 2 3 4])
(2 4 6 8 )

;simple fiter example on a list using odd?
user=> (filter odd? [1, 2,3,4,5])
(1 3 5)

;factorial using reduce
user=> (reduce * [1 2 3])
6

;if statement
user=> (if true (str “i am true”)(str “i am false”))
“i am true”