| f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Meglio | 01/08/12 05:37 | Currently I do:
What if we can do something like this:
The syntax is not the best, and we still have to deal with parameter names:
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. |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Kevin Wright | 01/08/12 05:45 | 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. |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Tony Morris | 01/08/12 05:59 | 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. > f1(*@a* "abc", f2(*a*, ..) ) >> f1(paramName = *@a* "abc", f2(*a*, ..) ) >-- Tony Morris http://tmorris.net/ |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Meglio | 01/08/12 06:56 | 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 |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Haoyi Li | 01/08/12 13:05 | 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. |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Jason Zaugg | 01/08/12 13:08 | On Wed, Aug 1, 2012 at 10:05 PM, Haoyi Li <hao...@gmail.com> wrote:One more, for fun: ((a: String) => f1(a, f2(a, ...))("abc") -jason |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Brian Maso | 01/08/12 13:27 | 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.m...@gmail.com> wrote: Best regards, Brian Maso (949) 395-8551 Follow me: @bmaso br...@blumenfeld-maso.com |
| Re: f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Ben Kyrlach | 01/08/12 14:17 | 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. |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | HamsterofDeath | 01/08/12 15:20 |
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 |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Tony Morris | 01/08/12 15:39 | I will write you up a code example next time I am in front of a computer. Remind me if I don't soon. |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Dave Stevens | 01/08/12 16:12 | 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)) |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Tony Morris | 01/08/12 22:01 |
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. |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | andreak | 02/08/12 00:32 | 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 |
| RE: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Razvan (Pub) Cojocaru | 02/08/12 11:25 | Is it just my browser or github just can’t break up long lines in their viewer? |
| RE: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Tony Morris | 02/08/12 15:15 | It's github. Try this https://t.co/5PxHuNRr |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | HamsterofDeath | 07/08/12 14:05 | 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.
|
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | HamsterofDeath | 07/08/12 14:35 | 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. |
| Re: [scala-user] f1(x, f2(x, b) ) - Is there a way to re-use value x without previously declaring it as val x? | Tony Morris | 07/08/12 20:42 |
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. |