Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map laziness in clojure

I am building a simple swing GUI in Clojure. I am trying to apply a single function to multiple GUI components by using map in the context of a let:

(map #(f % component4) [component1 component2 component3])

Where the components are all defined in the let.

Problematically, map is lazy, and the action is not applied to the components, however, I can force it by wrapping the above in a 'take'.

Is there a non lazy alternative to map? Or should I be going about this differently?

EDIT: Using counterclockwise in eclipse. I had different results using (use 'Lib :reload) from the REPL and using CTRL+Enter from the editor. Reloading would launch the GUI, but the problem described above would occur. The problem did not occur when using CTRL+Enter from the editor, therefore I think my description of the problem may be inaccurate. Regardless, doseq seems to be a better alternative to map in this scenario.

like image 446
user1064799 Avatar asked Nov 25 '11 00:11

user1064799


People also ask

Does Clojure have lazy evaluation?

Clojure is not a lazy language. However, Clojure supports lazily evaluated sequences. This means that sequence elements are not available ahead of time and produced as the result of a computation. The computation is performed as needed.

What is map in Clojure?

A map is a collection that holds key-value pairs. The values stored in the map can be accessed using the corresponding key. In Clojure there are two types of maps: Hash maps. Sorted maps.


3 Answers

I challenge your assertion that getting take involved makes any difference at all. If you wrapped it in doall or dorun it would do what you want, but you should consider using doseq instead of map for this sort of side-effect-only action.

Note

Originally posted as comment on question; copied to answer by popular demand.

like image 132
amalloy Avatar answered Oct 08 '22 19:10

amalloy


doseq is probably the best way to approach this. doseq is roughly equivalent to a "for-each" statement that loops over each element of a collection in many other languages. It is guaranteed to be non-lazy.

(doseq 
  [comp [component1 component2 component3]]
  (f comp component4))

Some general advice:

  • Use map and its lazy friends (including take, drop etc.) when you want a sequence as an output
  • Use doseq, doall, dotimes etc. when you are more interested in the side effects
like image 28
mikera Avatar answered Oct 08 '22 20:10

mikera


Wrapping your map in a doall will force its evaluation. or a better alternative is doseq which is used for things involving side effects.

like image 43
Hamza Yerlikaya Avatar answered Oct 08 '22 20:10

Hamza Yerlikaya