SharePoint Newbie
SharePoint Newbie

Reputation: 6082

How to curry two closures in Groovy?

I have a Java method:

void copy(Object src, Object dest);

I am using it in Groovy as such:

def copyGroovy = { p1, p2 -> copy(p1,p2) }
def copyFixP1 = { p1 -> copyGroovy.curry(p1) }
def cp = // How to define this?

How can I write the invocation in Groovy so that it looks like:

cp src dest

Any ideas?

Upvotes: 2

Views: 478

Answers (3)

Michael Easter
Michael Easter

Reputation: 24468

The following is a DSL answer that is arguably more of a kludge to solve a puzzle: it does not address currying syntax, but provides the veneer of cp src dest. But I hope it illustrates some Groovy features.

If we begin with the copy functions:

class Copy { 
    def copy = { a, b -> println "TRACER copy ${a} to ${b}" }
    def copyGroovy = { p1, p2 -> copy(p1,p2) }
    def copyFixP1 = { p1 -> copyGroovy.curry(p1) }
}

and define a Copier with some meta-programming methods:

class Copier {
    def copyContext 
    def runContext
    def p1, p2

    def methodMissing(String name, args) {
        p1 = args[0]
        return this
    }

    Object getProperty( String property ) {
        p2 = runContext.getProperty(property)
        copyContext.copyFixP1(p1)(p2)
    }
}

Then consider the following (assuming a single Groovy script as shown here):

// ----- main 

class Example {
    def src = "A"
    def dest = "B"

    def run = { ->
        def cp = new Copier(copyContext: new Copy(), runContext: this)

        // at long last:
        cp src dest
    }
}

new Example().run()

Upvotes: 2

Szymon Stepniak
Szymon Stepniak

Reputation: 42174

If you want to create a DSL like command chain you can take advantage of passing arguments without parentheses and/or dot notation. The closest form of cp command you mentioned in the question is something like:

cp (src) (dest)

cp in this case is a function that returns a closure that calls your Java's copy(Object src, Object dest) method. Something like this:

def cp(src) {
    return { dest ->
        copy(src, dest)
    }
}

If you would like to get rid of parentheses and you accept additional keyword, you could get something like this:

copy src to dest

which is an equivalent of:

copy(src).to(dest)

copy method can be implemented as:

def copy(src) {
    [to: { dest ->
        copy(src, dest)
    }]
}

And last, but not least - you can actually call this Java method as:

copy src, dest

You get rid of parentheses, but you need to add , to tell the compiler that you pass two arguments to this function.

Example

Below you can find example of all 3 combinations:

void copy(Object src, Object dest) {
    println "Copying ${src} to ${dest}..."
}

def copy(src) {
    [to: { dest ->
        copy(src, dest)
    }]
}

def cp(src) {
    return { dest ->
        copy(src, dest)
    }
}

def src = "/tmp/test.txt"
def dest = "/tmp/test2.txt"

// Example 1
copy src to dest

// Example 2
cp (src) (dest)

// Example 3
copy src, dest

Running this script produces following output:

Copying /tmp/test.txt to /tmp/test2.txt...
Copying /tmp/test.txt to /tmp/test2.txt...
Copying /tmp/test.txt to /tmp/test2.txt... 

You can read more about Groovy DSL features here

Upvotes: 2

ᴘᴀɴᴀʏɪᴏᴛɪs
ᴘᴀɴᴀʏɪᴏᴛɪs

Reputation: 7509

You can't write the invocation with space separated arguments like you would in Haskell (or other functional languages). Instead you need to write:

copyFixP1(src)(dst)

Also, you called the second variable as copyFixP1 but you are not actually fixing p1, copyFixP1 still needs an argument. Fixing would be to explicitly set the first argument of copyGroovy let's say to 'sourcePath' like so:

def copyFixedSrc = copyGroovy.curry('sourcePath')

You did curry it however so copyFixP1 is what I assume you wanted as cp.

Upvotes: 2

Related Questions