f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x?

165 views
Skip to first unread message

Meglio

unread,
Aug 1, 2012, 8:37:47 AM8/1/12
to scala...@googlegroups.com
Currently I do:

val a = "abc"
f1(a, f2(b, ...) )

What if we can do something like this:

f1(@a "abc", f2(a, ..) )

The syntax is not the best, and we still have to deal with parameter names:

f1(paramName = @a "abc", f2(a, ..) ) 


The idea here is that, if we do not need "abc" value other then for f1() call, make its declaration inline.

I'm not sure if this is possible somehow in Scala.

Kevin Wright

unread,
Aug 1, 2012, 8:45:57 AM8/1/12
to Meglio, scala...@googlegroups.com
Either stick with declaring the val, or re-write one of f1/f2 so that you don't need to supply the argument twice.

What you're asking for is a change in the language specification to support a rare and limited use case, when it's already perfectly trivial to just define the val.  Your chances of seeing this change happen are approximately 0.

Tony Morris

unread,
Aug 1, 2012, 8:59:08 AM8/1/12
to scala...@googlegroups.com
Yes. You want what is called the S combinator (SK combinator calculus).
It is the applicative functor for Function1.

The primary component of an applicative functor is a function with the form:
F[A => B] => F[A] => F[B]

If we replace F with Function1[X, _] by specialisation we get:
Function1[X, A => B] => Function1[X, A] => Function1[X, B]

Let's write this implementation:
f => g => x => g(x)(f(x))

You'll notice the similarity to your existing source.

If we make a method on Function1 (which we have called g) that accepts
an argument (which we have called f) and returns a function, let's call
it <*>, then the code looks this this:
g <*> f

Notice that x has gone. Your goal has been achieved.



On 01/08/12 22:37, Meglio wrote:
> Currently I do:
>
> val a = "abc"
> f1(a, f2(b, ...) )
>
>
> What if we can do something like this:
>
> f1(*@a* "abc", f2(*a*, ..) )
>
>
> The syntax is not the best, and we still have to deal with parameter names:
>
> f1(paramName = *@a* "abc", f2(*a*, ..) )
>
>
>
> The idea here is that, if we do not need "abc" value other then for f1()
> call, make its declaration inline.
>
> I'm not sure if this is possible somehow in Scala.
>


--
Tony Morris
http://tmorris.net/

Meglio

unread,
Aug 1, 2012, 9:56:32 AM8/1/12
to scala...@googlegroups.com, tmo...@tmorris.net
Tony, have read your comment 2 times but have not understood it. Any good link to more detailed explanation about SK combinator calculus?

Kevin, I'm trying to rewrite f1/f2, but not success yet. Maybe you can get back with some advice (see next).

I have bunch of functions for data extraction from HTML.
Each function can throw an exception, but exception text depends on element name being extracted, for example:

"result/pos TD is required but not found"
"result/pos can't be longer then 4 symbols"
and so on

Then, I combine and call these functions multiple times, passing in element name - so I get clear and fast feedback from crawler:

val pos = f1("result / pos", f2("result / pos", ..) )

I cannot make an f12(name, param1, ...) - just because I have many f functions and I combine them differently each time, eg:

val pos = f1("result / pos", f2("result / pos", ..) ) 
val track = f1("result / track", f2("result / track", ..) )

Is it clear or nonsense when explained in such way?

Also, I'm not sure if using implicit values for "result / pos" is a good idea.

Regards,
Anton

Haoyi Li

unread,
Aug 1, 2012, 4:05:00 PM8/1/12
to Meglio, scala...@googlegroups.com, tmo...@tmorris.net
The closest I can get is defining a function !! that will let you do

!!("abc", a => f1(a, f2(a, ..)))

or 

for(a <- !!"abc") f1(a, f2(a, ..))

or even using an anonymous class:

new !!("abc"){v = f1(a, f2(a, ..))}

none of which all that much better than

{val a="abc"; f1(a, f2(a, ..))}

Basically, you want to bind a value to a name and use it at the same time, as afaik that is not possible. The number of ways to bind new names is pretty small: Define a val/var, define a function/closure with parameters (or the equivalent for loop), or define a new class body. These are about as concise a "define & use" expression is going to get, all have more or less the same number of characters. 

IMHO using the {val a="abc"; f1(a, f2(a, ..))} expression is not bad; it's only 5 characters more than your ideal syntax, behaves exactly the same (the {} block can be used as an expression too), doesn't pollute any namespaces (since `a` is scoped to the {}s) and is pretty clear what it's doing. Aesthetically it looks ever so slightly awkward, but not bad for a semantically-correct expression that you get for "free" using the normal syntax of the language.

Jason Zaugg

unread,
Aug 1, 2012, 4:08:18 PM8/1/12
to Haoyi Li, Meglio, scala...@googlegroups.com, tmo...@tmorris.net
On Wed, Aug 1, 2012 at 10:05 PM, Haoyi Li <haoy...@gmail.com> wrote:
> The closest I can get is defining a function !! that will let you do
>
> !!("abc", a => f1(a, f2(a, ..)))
>
> or
>
> for(a <- !!"abc") f1(a, f2(a, ..))
>
> or even using an anonymous class:
>
> new !!("abc"){v = f1(a, f2(a, ..))}
>
> none of which all that much better than
>
> {val a="abc"; f1(a, f2(a, ..))}

One more, for fun:

((a: String) => f1(a, f2(a, ...))("abc")

-jason

Brian Maso

unread,
Aug 1, 2012, 4:27:59 PM8/1/12
to Meglio, scala...@googlegroups.com, tmo...@tmorris.net
Try:

val your_goal: String => Whatever =
    x => f1(x, f2(x))

And now you can call:

your_goal( some_expression_that_will_only_be_evaluated_once )

Brian Maso

On Wed, Aug 1, 2012 at 6:56 AM, Meglio <x.me...@gmail.com> wrote:



--
Best regards,
Brian Maso
(949) 395-8551
Follow me: @bmaso
br...@blumenfeld-maso.com

Ben Kyrlach

unread,
Aug 1, 2012, 5:17:55 PM8/1/12
to scala...@googlegroups.com
Tony Morris is (usually) right.

However, until you can better understand the S combinator, here are a few useful tips you might consider.

You can write a generic function like this...

def combine[A, B, C, D](f1: (A, B) => C, f2: (A, D) => B): (A, D) => C = {
  (a, d) => f1(a, f2(a, d))
}

Now you can write...

combine(f1, f2)("abc", whatever other input value)

If you need to nest it, you should be able to...

combine(f3, combine(f1, f2))("abc", whatever other input value)

This is probably where the S combinator would yield a better syntax with less repetition. Of that, I'm not entirely sure, since I don't have Tony's mastery of functional programming or mathematics.

Let me know if this makes sense.

HamsterofDeath

unread,
Aug 1, 2012, 6:20:31 PM8/1/12
to scala...@googlegroups.com
let me try to translate tony's answer to something requiring less knowledge, but more humor:
package hstar.randomstuff

/**
 * Created with IntelliJ IDEA.
 * User: HoD
 * Date: 01.08.12
 * Time: 22:17
 * To change this template use File | Settings | File Templates.
 */

object DeclarationGone {
  def main(args: Array[String]) {
    def f1(str:String, str2:String) = "xy"+str+str2
    def f2(str:String) = "z"+str
    //oldschool
    val a = "abc"
    val result = f1(a,(f2(a)))
    //but that is boring. we want some magic!
    def magic[X] = (fun: (X, X) => X, fun2: (X) => X) => (e: X) => fun(e, fun2(e))
    println(magic(f1, f2)("abc"))
    //but that it just a simple wrapper around the other functions. does it work for generic signatures? in clojure this would be easy :/
    val secondTry = (e:String) => (f1(e,f2(e)))
    println(secondTry("abc"))
    //mh. not that impressive either
    def magic2[X] = (fun: (X, X) => X, fun2: (X) => X) => (e: X) => fun2.andThen(e => (fun(_:X,e)))(e)(e)
    println(magic2(f1,f2)("abc"))
    //works, but wtf did i just do?
    def magic3[X] = (fun: (X, X) => X, fun2: (X) => X) => fun2.andThen(e => (fun(_: X, e))(e))
    println(magic(f1,f2)("abc"))
    //i think i understand what i just did. my favorite solution is:
    val magic4 = (a:String) => f1(a, (f2(a))) // just define a shortcut wrapper function once
    println(magic4("abc"))//and use it - more than once
    //honestly, i would scrap the functional mastery stuff and just write small def/function around the function composition
   
    //ok, one more try:
    implicit def magicComposition[A, B](fun:A => B) = new {
      def |>[C](fun2:(B)=>C) = (a:A) => fun2(fun(a))
    }

    val magic5 = (in:String) => ((f2 _) |> (e => f1(in, e)))(in)
    println(magic5("abc"))
    //now that i managed to use cryptic symbold and implicits, i feel satisfied :)
  }
}

i prefer the fourth solution. hide the repetition behind another function and you're good

Tony Morris

unread,
Aug 1, 2012, 6:39:15 PM8/1/12
to Meglio, scala...@googlegroups.com

I will write you up a code example next time I am in front of a computer. Remind me if I don't soon.

Dave Stevens

unread,
Aug 1, 2012, 7:12:15 PM8/1/12
to Tony Morris, Meglio, scala...@googlegroups.com
I believe this is a simple example.

scala> import scalaz._; import Scalaz._;
import scalaz._
import Scalaz._

scala> def g = (p1: String) => "g(" + p1 + ")"
g: String => java.lang.String

scala> def f = (p1: String) => (p2: String) => "f(" + p1 + ", " + p2 + ")"
f: String => String => java.lang.String

scala> def fg = g <*> f
fg: String => java.lang.String

scala> fg("abc")
res0: java.lang.String = f(abc, g(abc))

Things get a little more hairy when 'f' and 'g' have more parameters. Tony, if you get around to an example, would you do something less trivial than my example above?

Here's my attempt at something closer to OP using S Combinators. Might as well add the extra String to the parameter list of 'f12' though I think.

scala> def f1 = (x: Int) => (c: String) => (rf2: String) => "f1(" + x.toString + ", " + c + ", " + rf2 + ")"
f1: Int => String => String => java.lang.String

scala> def f2 = (y: Int, z: Double) => (c: String) => "f2(" + y.toString + ", " + z.toString + ", " + c + ")"
f2: (Int, Double) => String => java.lang.String

scala> def f12 = (x: Int, y: Int, z: Double) => (f2(y, z) <*> f1(x))
f12: (Int, Int, Double) => String => java.lang.String

scala> f12(10, 11, 12)("abc")
res1: java.lang.String = f1(10, abc, f2(11, 12.0, abc))

Tony Morris

unread,
Aug 2, 2012, 1:01:32 AM8/2/12
to Tony Morris, Meglio, scala...@googlegroups.com
Here is a compileable source file. It contains commentary throughout and hopefully makes the point clearer.

https://gist.github.com/3233807

As it happens, this subject gets a fair amount of exposure in Functional Programming in Scala[ http://www.manning.com/bjarnason/ ], with exercises leading up to this point and also going beyond.

Andreas Joseph Krogh

unread,
Aug 2, 2012, 3:32:23 AM8/2/12
to scala...@googlegroups.com
On 08/02/2012 07:01 AM, Tony Morris wrote:
Here is a compileable source file. It contains commentary throughout and hopefully makes the point clearer.

https://gist.github.com/3233807

As it happens, this subject gets a fair amount of exposure in Functional Programming in Scala[ http://www.manning.com/bjarnason/ ], with exercises leading up to this point and also going beyond.

Good shit, just ordered my copy!
-- 
Andreas Joseph Krogh<and...@officenet.no>  - mob: +47 909 56 963
Senior Software Developer / CEO - OfficeNet AS - http://www.officenet.no
Public key: http://home.officenet.no/~andreak/public_key.asc

Razvan Cojocaru

unread,
Aug 2, 2012, 2:25:43 PM8/2/12
to tmo...@tmorris.net, Meglio, scala...@googlegroups.com

Is it just my browser or github just can’t break up long lines in their viewer?

Tony Morris

unread,
Aug 2, 2012, 6:15:22 PM8/2/12
to Razvan Cojocaru, scala...@googlegroups.com, Meglio

It's github.

Try this https://t.co/5PxHuNRr

HamsterofDeath

unread,
Aug 7, 2012, 5:05:10 PM8/7/12
to scala...@googlegroups.com
did i get that right?
/**
�* Created with IntelliJ IDEA.
�* User: HoD
�* Date: 01.08.12
�* Time: 22:17
�* To change this template use File | Settings | File Templates.
�*/

object DeclarationGone {
� def main(args: Array[String]) {
��� def f1(str: String, str2: String) = "xy" + str + str2
��� def f2(str: String) = "z" + str
��� val outer = f1 _
��� val inner = f2 _
��� implicit def pimp[X,X2,R](f:(X,X2) => R) = new {
����� def <*>(inside:(X => X2)) = (e:X) => f(e,inside(e))
��� }
��� println((outer <*> inner)("hello combinator"))
��� println(f1("hello combinator",f2("hello combinator")))
� }
}

the result is the same, so i guess staring at tony's first email really did transform into some form of understanding after some time.


Am 03.08.2012 00:15, schrieb Tony Morris:

It's github.

Try this https://t.co/5PxHuNRr

On Aug 3, 2012 4:25 AM, "Razvan Cojocaru" <p...@razie.com> wrote:

Is it just my browser or github just can�t break up long lines in their viewer?

�

From: scala...@googlegroups.com [mailto:scala...@googlegroups.com] On Behalf Of Tony Morris
Sent: August-02-12 1:02 AM
To: Tony Morris
Cc: Meglio; scala...@googlegroups.com
Subject: Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x?

�

Here is a compileable source file. It contains commentary throughout and hopefully makes the point clearer.

https://gist.github.com/3233807

As it happens, this subject gets a fair amount of exposure in Functional Programming in Scala[ http://www.manning.com/bjarnason/ ], with exercises leading up to this point and also going beyond.

On 02/08/12 08:39, Tony Morris wrote:

I will write you up a code example next time I am in front of a computer. Remind me if I don't soon.

On Aug 1, 2012 11:56 PM, "Meglio" <x.me...@gmail.com> wrote:

Tony, have read your comment 2 times but have not understood it. Any good link to more detailed explanation about SK combinator calculus?

�

Kevin, I'm trying to rewrite f1/f2, but not success yet. Maybe you can get back with some advice (see next).

�

I have bunch of functions for data extraction from HTML.

Each function can throw an exception, but exception text depends on element name being extracted, for example:

�

"result/pos TD is required but not found"

"result/pos can't be longer then 4 symbols"

and so on

�

Then, I combine and call these functions multiple times, passing in element name - so I get clear and fast feedback from crawler:

�

val pos = f1("result / pos", f2("result / pos", ..) )

�

I cannot make an f12(name, param1, ...) - just because I have many f functions and I combine them differently each time, eg:

�

val pos = f1("result / pos", f2("result / pos", ..) )�

val track = f1("result / track", f2("result / track", ..) )

�

Is it clear or nonsense when explained in such way?

�

Also, I'm not sure if using implicit values for "result / pos" is a good idea.

�

�

HamsterofDeath

unread,
Aug 7, 2012, 5:35:41 PM8/7/12
to scala...@googlegroups.com
the whole other stuff you posted was to abstract the application itself "f(e,inside(e)" away and pull it in via an implicit, yes?
i don't know how all you guys see it, but for me, reading code like this is about 10x more difficult than reading a simple english sentence targeted at a 5 year old child and work my way from there. i can easily go from a concrete, artificially simplified example to the general case (which is what our braines are designed for). the other way is much more difficult for me.

Tony Morris

unread,
Aug 7, 2012, 11:42:14 PM8/7/12
to scala...@googlegroups.com
I bet if I asked you to reverse a list of integers, you wouldn't use Int in the type signature. You'd parameterise it.

Similarly for Applicative, I didn't specialise it to Function1[T, _], although that is what the original use-case was. The advantage of this is that your type signature gives away a *lot* of information about what the function does. For example, your parameterised reverse function is not going to add 10 to each element even though you could use it to do so. This is related to Philip Wadler's, Theorems for Free. A further advantage is that by recognising that it fits this pattern, you can exploit all the implications. For example, did you know what you sequence *any* Applicative? That is: List[F[A]] => F[List[A]] for any Applicative[F]. In this use-case, this means you can have sequence: List[T => A] => T => List[A]. You don't need to look very far to see this pattern repeated over and over in various libraries and mailing list questions.

The disadvantage of course is nailing down how you come about recognising this pattern. There is no definite way. However, I do know that there are a few naysayers out there and they will probably never arrive at an understanding. If you wish to dedicate yourself to the subject, then there are many who will help you. If not, then fine. It's a matter of familiarity for you and a matter of balancing many approaches to arrive at an understanding for an instructor. It is *much harder* for an instructor to hold the suspense of disbelief of the student than it is for the student -- you need only read some of the nonsense on the internetz to see that. Just ignore it, I say or giggle if it is warranted.

There are some people who insist that this way or that way is The Correct Approach, simply because they claim it worked out for them (even this itself is often questionable). They are just wrong and I cannot help them.

Godspeed.
Reply all
Reply to author
Forward
0 new messages