3

How can one translate the following code

while ((readInteger = fileInputStream.read()) != -1) {
.....
}

in clojure ? I need the value of readInteger in further parts of the code but also the '!= -1' needs to take place inside the while conditional.

4 Answers 4

6

some general patterns for adapting things to the Clojure syntax

  1. move the ( to the left of the function or opperator.
  2. move opperators to the left of the things they work on and surround with ( )

so you could start like this:

(while (not= (.read fileInputStream) -1 ... and so on.

then, since you need to use the readInteger value later in the code let's talk about naming values and looping. If you just wanted to read a value once and give it a name you could do it like this:

(let [readInteger  (.read fileInputStream)]
  ... your code here)

Since you want to do it in a loop, then let's use loop instead of let:

(loop [readInteger  (.read fileInputStream)]
  ... your code here
  (if (not= readInteger -1)
    (recur (.read fileInputStream))))

or for (which is not the "for loop" from other languages)

(for [readInteger   (repeatedly #(.read fileInputStream))
      :while (not= readInteger -1)]
  ... do somethign with readInteger ...)

For generates sequences of results rather than just looping like it does in other languages.

Then the next step in clojuring is to think about how to split the reading the data from processing it. We can:

  1. make a sequence of all the data
  2. process each data

something like this:

(let [data (line-seq fileInputStream)]
  (map #(Integer/parseInt %) data)
  ...)

There are functions in the standard library for converting a great many things into sequences, and a bunch of functions for doing a great many things with sequences.

Sign up to request clarification or add additional context in comments.

Comments

3

Don't solve this problem with while, which requires you to do your test at the beginning of the loop. Instead, think about a recursive function, which can decide at any part of its body whether to make the recursive call or not. Any iterative loop can be converted into a tail-recursive function using loop/recur; here's an example of how to do it with your loop.

(loop []
  (let [read-integer (.read file-input-stream)]
    (when (not= read-integer -1)
      (...)
      (recur))))

Comments

2

Here are two similar examples like amalloy suggested:

(ns xyz...
  (:require  [clojure.java.io :as io] )
  (:import [java.io StringReader] ))

(newline) (newline)
(let [reader-2 (io/reader (StringReader. "first")) ]
  (loop []
    (let [curr-char-int (.read reader-2)]
      (when (not= -1 curr-char-int)
        (print (char curr-char-int) " ")
        (recur)))))

(newline) (newline)
(let [reader-2 (io/reader (StringReader. "second")) ]
  (loop [curr-char-int (.read reader-2)]
    (when (not= -1 curr-char-int)
      (print (char curr-char-int) " ")
      (recur (.read reader-2)))))

With result:

> lein run

f  i  r  s  t  

s  e  c  o  n  d  

In the first case it takes an extra let statement, but doesn't duplicate the part (.read reader-2) like the 2nd case does.

Comments

0

Using threading macro:

(->> (repeatedly #(.read fs))
     (take-while (partial not= -1))
     (map str))

Replace (map str) with whatever function you want to operate on the stream. For example, to calculate the sum:

(->> (repeatedly #(.read fs))
     (take-while (partial not= -1))
     (reduce +))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.