Clojure spit behaviour on byte arrays - file

The following code :
(spit "/Users/nha/tmp/spit.txt" (.getBytes "hello"))
produces a file containing "[B#71e054bc", which is independent of the content ("hello" in this case) since this is the JVM representation of the address of a byte array.
However the following works (taken from this SO post):
(clojure.java.io/copy
(.getBytes "hello")
(java.io.File. "/Users/nha/tmp/spit.txt"))
And the file then contains the correct content "hello".
Why does spit behave like this ? Is there a way to expand it's behaviour for bytes ?

This problem isn’t particular to byte arrays.
(spit "spit.txt" (Object.))
(slurp "spit.txt") ;; => "java.lang.Object#90b293d"
Looking at the source of spit you’ll see that it simply tries to obtain the string representation of the argument before writing it out.
You could try to wrap any byte array in a new string before writing, but take care to select the proper encoding.
;; platform-dependent!
(spit "spit.txt" (String. b))
;; better
(spit "spit.txt" (String. b java.nio.charset.StandardCharsets/UTF_8))

the reason is that the content is passed to str
you can check that via (source spit):
user=> (source spit)
(defn spit
"Opposite of slurp. Opens f with writer, writes content, then
closes f. Options passed to clojure.java.io/writer."
{:added "1.2"}
[f content & options]
(with-open [^java.io.Writer w (apply jio/writer f options)]
(.write w (str content))))
; - ^^^ - here
therefor you get the string representation of the byte-array written
EDIT: and since spit the "inverse" of slurp which gives you a string, it makes sense and is consistent behaviour

Related

How to transform the result of an iterator into an array in Ruby

I want to know how to transform the results of an iterator into an array. I have presented two options below, and both run, but yield the result in the wrong format.
This is the result I am getting vs what is expected.
enter image description here
I am trying to transform the iterator results into an array with Array(), but it does not work.
I tried:
Block code with .keep_if methods
for if conditionals with Array() to make the transformation.
What I expect:
An array of non-negative integers. The input (l) is an array of random integers and strings.
My code options are as follows:
Option 1:
def filter_list(l)
l.delete_if {|li| li.class ==String || li<0}
puts l
end
Option 2:
def filter_list(l)
arr=[]
for i in l
if i.class == Integer && i>=0
arr1=arr.push(i)
end
end
puts Array(arr1)
end
Why don't the above options work?
Why don't the above options work?
You have a syntax error here:
Def filter_list(l)
↑
Method definitions use the def keyword with a lower-case d. What you have written here will be interpreted as a method call to a method named Def, passing filter_list(l) as an argument, i.e. that code will be interpreted as
self.Def(filter_list(l))
Which then means that Ruby is not expecting to see an end keyword.
To output the result in the expected format just use p instead of puts.
From the docs of puts
[...] If called with an array argument, writes each element on a new line. Each given object that isn't a string or array will be converted by calling its to_s method. [...]
Whereas the p method doesn't call to_s but inspect before printing the output:
For each object, directly writes obj.inspect followed by a newline to the program's standard output.
The default string representation, returned by inspect for an array, looks like your expected output.

How to write binary into file in Crystal

I have an array of UInt32, what is the most efficient way to write it into a binary file in Crystal lang?
By now I am using IO#write_byte(byte : UInt8) method, but I believe there should be a way to write bigger chunks, than per 1 byte.
You can directly write a Slice(UInt8) to any IO, which should be faster than iterating each item and writing each bytes one by one.
The trick is to access the Array(UInt32)'s internal buffer as a Pointer(UInt8) then make it a Slice(UInt8), which can be achieved with some unsafe code:
array = [1_u32, 2_u32, 3_u32, 4_u32]
File.open("out.bin", "w") do |f|
ptr = (array.to_unsafe as UInt8*)
f.write ptr.to_slice(array.size * sizeof(UInt32))
end
Be sure to never keep a reference to ptr, see Array#to_unsafe for details.

Filter file by length BEFORE saving haskell

A similar question has been asked, but with a list in hand:
Filter list items by length in Haskell
I already know how to get a word list from a file
getWords path = do contents <- readFile path
return (lines contents)
And then I can filter it to get words of specific length, but...
What I am wondering is if there is a way (preferably not in point-free style - unless necessary) to filter the file by length before saving it as a list of words.
For example, words.txt is file of words with 1 word per line.
filteredWords <- filter (\x -> length x == 3) *Read words.txt in place*
Use the fact that IO is also an instance of Functor
filteredWords <- fmap (filter (\x -> length x == 3)) $ getWords path
Since you asked about how to do it without using getWords: you can use the function composition operator ..
filteredWords <- fmap (filter (\x -> length x == 3) . lines) $ readFile path
I think readFile is in Prelude, if it's not then it will be in System.IO
I am not sure I completely understand this question. It centers around the notion of "before saving it as a list of words", which seems to be misleading in a lazy language. In Haskell, doing
let list1 = someLongList
list2 = filter p list1
in use list2 -- (but do not use list1)
will not cause list1 to be stored in memory completely: rather, elements not satisfying p will be discarded immediately.
Hence, the notion of filtering a list before "saving" it is not meaningful: this is a standard optimization that the compiler will do for you.
Rather, separating input/output and filtering is the preferred way. The alternative, namely mixing I/O and pure computation in the code is generally regarded as a worse approach. Haskell types also encourage the first, simpler, approach.
Yes. Here is an example using pipes that avoids materializing the full list of words. Only the words of the specified length will be retained in memory:
import Pipes
import qualified Pipes.Prelude as Pipes
import qualified System.IO as IO
filteredWords :: FilePath -> IO [String]
filteredWords path =
IO.withFile path IO.ReadMode (\handle -> Pipes.toListM (
Pipes.fromHandle handle >-> Pipes.filter (\x -> length x == 3) ))
So, for example, if your file had 1,000,000 words, but only 4 of them had length 3, then this program would only generate a list of length 4. All the other elements would be discarded immediately after they were read and not stored in memory in some intermediate list.

Haskell read lines of file

I want to read a whole file into a string and then use the function lines to get the lines of the string. I'm trying to do it with these lines of code:
main = do
args <- getArgs
content <- readFile (args !! 0)
linesOfFiles <- lines content
But I'm getting the following error by compiling ad it fails:
Couldn't match expected type `IO t0' with actual type `[String]'
In the return type of a call of `lines'
In a stmt of a 'do' block: linesOfFiles <- lines content
I thought by binding the result of readFile to content it will be a String DataType, why isn't it?
I thought by binding the result of readFile to content it will be a String DataType, why isn't it?
It is a String indeed, that's not what the compiler complains about. Let's look at the code:
main = do
args <- getArgs
content <- readFile (args !! 0)
Now content is, as desired, a plain String. And then lines content is a [String]. But you're using the monadic binding in the next line
linesOfFiles <- lines content
in an IO () do-block. So the compiler expects an expression of type IO something on the right hand side of the <-, but it finds a [String].
Since the computation lines content doesn't involve any IO, you should bind its result with a let binding instead of the monadic binding,
let linesOfFiles = lines content
is the line you need there.

Haskell: Inserting every line from a file into a list

I'm currently working on project with Haskell, and have found myself some trouble. I'm supposed to read and insert into a list each line in a "dictionary.txt" file, but I can't seem to do so. I've got this code:
main = do
let list = []
loadNums "dictionary.txt" list
loadNums location list = do
inh <- openFile location ReadMode
mainloop inh list
hClose inh
mainloop inh list = do
ineof <- hIsEOF inh
if ineof
then return ()
else do
inpStr <- hGetLine inh
inpStr:list
mainloop inh list
It is supposed to get every line (I know it does get every line, since replacing the "inpStr:list" with a "putStrLn inpStr" works correctly, displaying all lines), and insert it into a list but I get the following error:
Couldn't match expected type `IO' against inferred type `[]'
Probably because the hGetLine isn't a String, but a IO String, which I have no idea how to handle in order to obtain a proper string I can insert in my list. I have no idea how this could be solved, or what the problem is exactly, but if anyone has any idea of how to properly get every line in a file into a list, I'd appreciate it.
Thanks in advance!
Unless this is for homework or something, there's no reason to use so much effort. Reuse is lazy!
getLines = liftM lines . readFile
main = do
list <- getLines "dictionary.txt"
mapM_ putStrLn list
But as you seem to still be learning Haskell, it is important for you to understand what CesarB has written.
In the line where the error happens, Haskell is expecting "IO a", but you are giving it a []. Simplifying things a lot, on a do block on the IO monad, every line is either:
Something which returns a value of the "IO a" type; the value of the "a" type within it is discarded (so the "a" is often "()")
A <- expression, which does the same thing but instead of discarding the value of the "a" type gives it the name to the left of the <-
A let, which does nothing more than give a name to a value
In that do block, the "hGetLine inh" returns an "IO String", and the String within it is extracted and given the name inpStr. The next line, since it's neither a let or a <-, should have a type "IO a", which it doesn't (thus causing the compiler error). What you can do instead, since you already have the String, is a let:
let list' = inpStr:list
This creates a new list consisting of the String followed by the original list, and gives it the name of "list' ".
Change the following line to use "list' " instead of "list" (thus passing it the new list). That line calls (recursively) mainloop, which will read one more line, call itself, and so on. After reading the whole file, it will return something with the "IO ()" type. This "IO ()" will be returned to the do block at loadNums. Congratulations, you just created a list with the lines read from the file, in reverse order (since you were appending to the head of the list), and then did nothing to it.
If you want to do something to it, change the "return ()" to "return list"; the return will generate a value of type "IO [String]", with the list within it (return does nothing more than encapsulating the value), which you can extract at loadNums with the <- syntax.
The rest is left as an exercise to the reader.

Resources