passing value to functions

48 views
Skip to first unread message

Tuba Lambanog

unread,
Jul 28, 2011, 5:29:12 AM7/28/11
to Clojure
Hello,

I'm trying to pass a variable through a series of functions, which may
change the value of the variable. However, the next function in line
uses the original value, rather than the changed value. Here's a
pseudo-code of what I'm doing.

(defn process-1 [s]
; change value of s then return it
s)

(def s "something")
(do
(process-1 s) ; variable s is changed here
(process-2 s)) ; process-2 uses the original value of s, not the
return value from process-1

Thanks for the help.

Perhaps a sub-forum for beginners? Kind of embarrassing to ask here
questions that are so newbie-ish.

Baishampayan Ghose

unread,
Jul 28, 2011, 5:34:52 AM7/28/11
to clo...@googlegroups.com
> I'm trying to pass a variable through a series of functions, which may
> change the value of the variable. However, the next function in line
> uses the original value, rather than the changed value. Here's a
> pseudo-code of what I'm doing.
>
> (defn process-1 [s]
> ; change value of s then return it
>  s)
>
> (def s "something")
> (do
>  (process-1 s)      ; variable s is changed here
>  (process-2 s))    ; process-2 uses the original value of s, not the
> return value from process-1

There is no idiomatic way to do this in Clojure. If you explain the
problem (and not your proposed solution) we might be able to find a
nice and clean way of solving the problem.

Regards,
BG

--
Baishampayan Ghose
b.ghose at gmail.com

OGINO Masanori

unread,
Jul 28, 2011, 5:42:16 AM7/28/11
to clo...@googlegroups.com
http://clojure.org/state may help you to know Clojure's "value".
; AFAIK Java's string is also immutable...isn't it?

--
Name: OGINO Masanori (荻野 雅紀)
E-mail: masanor...@gmail.com

Laurent PETIT

unread,
Jul 28, 2011, 5:44:12 AM7/28/11
to clo...@googlegroups.com
Hi,

2011/7/28 Tuba Lambanog <tuba.l...@gmail.com>

Hello,

I'm trying to pass a variable through a series of functions, which may
change the value of the variable. However, the next function in line
uses the original value, rather than the changed value. Here's a
pseudo-code of what I'm doing.

(defn process-1 [s]
; change value of s then return it
 s)

(def s "something")
(do
 (process-1 s)      ; variable s is changed here
 (process-2 s))    ; process-2 uses the original value of s, not the
return value from process-1


beware, "change" in the clojure world means "computing a new value based on an old one" (as opposed to creating a new value "almost from scratch").

So for example, when you add an element to a map :
(def m1 {:a 1})
(def m2 (assoc m1 :b 2))

you're really creating a new value.
People will sometimes say they "change" m1, but it's not true, it's more to say that m2 is derived from m1 (sharing most things with m1).

So you need to "pipe" the return value of process-1 into process-2.

The "manual way" to do the pipe :
(let [s-p1 (process-1 s)
      s-p2 (process-2 s-p1)]
  s-p2)

The "short" way (preferred in your case) :
(-> s process-1 process-2)

HTH,

--
Laurent
 
Thanks for the help.

Perhaps a sub-forum for beginners? Kind of embarrassing to ask here
questions that are so newbie-ish.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Thorsten Wilms

unread,
Jul 28, 2011, 7:03:38 AM7/28/11
to clo...@googlegroups.com
On 07/28/2011 11:29 AM, Tuba Lambanog wrote:

> I'm trying to pass a variable through a series of functions, which may
> change the value of the variable. However, the next function in line
> uses the original value, rather than the changed value. Here's a
> pseudo-code of what I'm doing.

I think you should provide more context. Why, if that is the case at
all, do you want to pass an argument through functions that do not work
with it?

How many arguments does each fn in the line take (and what do they
evaluate to)?

Is it a fixed or a variable number of functions?


> Perhaps a sub-forum for beginners? Kind of embarrassing to ask here
> questions that are so newbie-ish.

Really no reason to feel embarrassed and I doubt the experts here would
like to monitor an additional space ...


--
Thorsten Wilms

thorwil's design for free software:
http://thorwil.wordpress.com/

Tuba Lambanog

unread,
Jul 28, 2011, 12:18:38 PM7/28/11
to Clojure
I'm trying to write a spelling 'standardizer' for a language that has
no standardized spelling. There are about 25 spelling rules, and a few
more may be added. . The input words, streamed one at a time from a
text file, go through these rules, and may change if conditions are
met. To take English examples, "wouldn't" would be converted to
"would", "labour" to "labor" (assuming a particular spelling
standard), "criticise" to "criticize", "prolog" to "prologue". My knee-
jerk reaction is to implement the rules as individual functions (what
a joy to do this in Clojure!). The functions may be called in
different orders depending on, say, the number of syllables of the
input word).

As suggested by Masanori, I read up on Clojure state -- and what a
revelation that was. I understood it enough to say I don't understand
it, because, my initial blockheaded reaction was, so how's sending
back a value different from the Clojure way, since the value sent back
is the state of the identify x at that point in time.

I will try Laurent's suggestion.

Thanks for the enlightenment!

tuba

Tuba Lambanog

unread,
Jul 28, 2011, 12:34:20 PM7/28/11
to Clojure
Hi, Thorsten,
<<
Why, if that is the case at
> all, do you want to pass an argument through functions that do not work
> with it?
>>

The determination of whether a called function will apply is left as a
responsibility of the function itself, rather than the calling
function. The motivation is that a function may be called from a
number of places. Perhaps there's a better way?

Thanks for the encouragement to ask questions here.

tuba

On Jul 28, 5:03 am, Thorsten Wilms <t...@freenet.de> wrote:

Thorsten Wilms

unread,
Jul 28, 2011, 3:22:59 PM7/28/11
to clo...@googlegroups.com
On 07/28/2011 06:34 PM, Tuba Lambanog wrote:

> The determination of whether a called function will apply is left as a
> responsibility of the function itself, rather than the calling
> function. The motivation is that a function may be called from a
> number of places. Perhaps there's a better way?

The called function cannot decide to not be applied, but it may either
evaluate to its argument (assuming unary), or a value derived from that
argument.

I guess pattern matching would be nice here, but even without, you could
perhaps split the conditions from the actions. Is there any reason to
test additional rules after one matches, or would it be beneficial to
stop after a match? That would make it similar to URL routing like e.g.
Moustache does it.

From your description, it did sound like you want to call the 2nd
function with the original argument, not the result of the 1st function.
But how would you accumulate all the results, then?

Alan Malloy

unread,
Jul 28, 2011, 3:56:34 PM7/28/11
to Clojure
You don't need to "change" the original value at all - you just want
to compute a new value, which, as Thorsten says, may be the same as
the original, or not. Then pass that new value to another function
that may decide to change it again, or not, and then...


(defn fix-ou [word]
(clojure.string/replace word #"ou" "o"))

(defn fix-ize [word]
(clojure.string/replace word #"ise" "ize"))

(defn apply-all-fixes [word]
(fix-ize (fix-ou word)))

(defn fix-whole-sentence [words]
(for [word words]
(apply-all-fixes word)))

user> (fix-whole-sentence ["don't" "criticise" "the" "labour"
"party"])
("don't" "criticize" "the" "labor" "party")

Resty Cena

unread,
Jul 28, 2011, 4:32:58 PM7/28/11
to clo...@googlegroups.com
Hi, Thorsten,

Yes, you're right, once inside a function, the function is already being applied. I mean that within the function, there's a test for whether the input variable needs to be changed or not. Sort of vacuous application if conditions are not met. 

Yes, an enriched facility for pattern matching would be nice. I use a bit of regular expression, a last resort for me.

<< Is there any reason to test additional rules after one matches, or would it be beneficial to stop after a match? >>

Yes, the input may violate more than one spelling rule. So it is essential that the output of a function feeds the next one. 

Thanks for the help.

Tuba



--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

Resty Cena

unread,
Jul 28, 2011, 4:53:47 PM7/28/11
to clo...@googlegroups.com
Hi, Alan,

I can see that your suggestion will work. The key, as I understand it, is the embedding of functions, thus:

 (fix-ize (fix-ou word)))

which is indeed a Lisp-y way of doing things. It seems imperatively I miss elegant one-liners such as this. 

I'm right now close to getting Laurent's approach to work. 

Thanks much for your help.

Tuba

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

Tuba Lambanog

unread,
Jul 28, 2011, 5:32:29 PM7/28/11
to clo...@googlegroups.com
Hi, Laurent,

Your suggestion of manually piping intermediate results works. Thank you very much!

Tuba

OGINO Masanori

unread,
Jul 28, 2011, 7:42:32 PM7/28/11
to clo...@googlegroups.com
Laurent's way and Alan's way have different surfaces, but same mean.

(-> word fix-ou fix-ize)
(fix-ize (fix-ou word))

You can check it using clojure.walk/macroexpand-all.

user=> (macroexpand-all '(-> "labour" fix-ou fix-ize))
(fix-ize (fix-ou "labour"))

Indeed you can choose only one way, I suggest considering two ways.
Sometimes using -> is easy to read, and sometimes it is hard to do.
(Readability is the matter in this case, right?)

Resty Cena

unread,
Jul 28, 2011, 11:11:36 PM7/28/11
to clo...@googlegroups.com
Hi, Masanori,
Yes, I noticed the similarity. I'm using Laurent's 'manual way' for now. I'll look at Alan's and Laurent's more concise solution in a few days. The "manual way" is easy to debug as all I have to do is println the intermediate results.
Thanks.
Tuba


2011/7/28 OGINO Masanori <masanor...@gmail.com>
--

Alan Malloy

unread,
Jul 29, 2011, 12:34:03 AM7/29/11
to Clojure
On Jul 28, 8:11 pm, Resty Cena <restyc...@gmail.com> wrote:
> Hi, Masanori,
> Yes, I noticed the similarity. I'm using Laurent's 'manual way' for now.
> I'll look at Alan's and Laurent's more concise solution in a few days. The
> "manual way" is easy to debug as all I have to do is println the
> intermediate results.

You can actually debug the -> versions even more easily, if you borrow
my `?` debugging macro, available at
https://github.com/amalloy/amalloy-utils/blob/master/src/amalloy/utils/debug.clj

Then you can simply write
(-> input
fix-ou
? ;; see result of fix-ou phase
fix-ize
? ;; see result of fix-ize phase
)

Tuba Lambanog

unread,
Jul 29, 2011, 2:49:10 AM7/29/11
to clo...@googlegroups.com
Alan,
The macro is great (output could use a bit of formatting for readability, but, hey, I'm not complaining). Thank you very much. 
Tuba


--
Reply all
Reply to author
Forward
0 new messages