Haskell: Inserting every line from a file into a list - file

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.

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.

2nd object in array ignored (godot)

I have a .csv file holding scores. This is what it looks like:
"name",10
The .csv is parsed with this function:
func _ready():
var file = File.new()
file.open("user://scores.csv", file.READ)
while !file.eof_reached():
line = file.get_csv_line()
text = text + "%s: %s" % [line[0], line[1]] + "\n" ## Invalid get index: '1' (on base: PoolStringArray)
The file must be ending in a new line. As a result, you get two lines while reading it. The first one has what you expect ([name, 10]), the second one is empty, causing an error when you try to index it.
When I tested this, the last line does not come as an empty array, but as an array with a single empty string. Looking around, this behavior has been there for a while. However, I found no bug reports or proposals, I wonder if there is a reason, or this was just overlooked.
You can check the number of columns you got. For example, the code below would skip any lines with not enough fields for your case:
if line.size() < 2:
continue
And this code will specifically target the extra line:
if file.eof_reached() and line.size() == 1 and line[0] == "":
break

How to use an array of functions in Swift

I have read all the posts I can find here about arrays of functions - great you can do it. I figured. But none of the posts show practically how to use them (at least not what I'm trying to do). Here's what I want - they can all take the same args, but that's not a requirement.
This article is close, and will allow me to loop through to execute each function (which meets the first goal).
https://stackoverflow.com/a/24447484/11114752
But... what if I want to execute a single function by reference?
In other words, how to call just the referenced Arity2 function - for example:
// None of these work (with or without the parameter labels)
funcs.Arity2(n: 2, S: "Fred) // value of type [MyFuncs] has no member .Arity2
funcs[Arity2](n: 2, S: "Fred") // no exact matches to call in subscript
funcs[.Arity2](n: 2, S: "Fred") // Cannot call value of non-function type...
let fn = funcs.first(where: { a whole ton of permutations here to try to match Arity2 }) -- a whole lotta frustrating nope...
Help, please! Nothing I've tried works. The pre-compiler just goes in circles making suggestions that don't pan out and it will not compile.
EDIT:
The reason for the array in the first place is that I'm going to have a quite a few functions, and I don't know what they all are in advance. Essentially, I want a plugin type of architecture. Where I can add to the list of functions (ideally within an extension of the class, but that's another problem..) and not change the processing loop that executes each function in order.
I assume you need something like
_ = funcs.first {
if case let MyFuncs.Arity2(f) = $0 {
f(2, "Fred")
return true
}
return false
}
It can be achieved in a much simpler way if you know the position of the function in the array.
Assuming you have:
func someFunc(n: Int, s: String) {
print("call \(n) \(s)")
}
var funcs = [MyFuncs.Arity2(someFunc)]
you can do:
if case .Arity2(let f) = funcs.first {
f(2, "Fred")
}
By replacing funcs.first with funcs[i] you can access the i-th index (first make sure it does exist).

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.

functions,tables and for in Lua

Right now I'm doing some tests but I cant seem to find what is wrong with this code - any idea?
function IATetris(Pieza,Rotacion,Array)
io.write("The table the script received has: ",Pieza,"\n")
RotacionInicial = Rotacion
PosInicial = 7
final = #Array --this gets the size of the array
i = 1
for y = 1, 20 do --the array of my tetris board is 20 in x and 14 in y so it would be something like this Array2D[20][14]
io.write(" First for y ",y,"\n")
Array2D[y]={} --clearing the new array
for x = 1,14 do
io.write(" First for x ",x,"\n")
if i == final then break end
io.write(" First for i",i,"\n")
Array2D[y][x] = Array[i]
i= i+1 --seems like you cant use i++ in lua
end
end
end
What I'm doing is getting 2 integers and 1 Array. I'm having to write in the console to check where the program is actually going, and what I'm getting is...
The first log message: "The table the script received has: "
and the second log message: " First for y "
But I don't get any further than those so probably the program is crashing there? This function is being called like every 20 seconds or so. I have really no idea why this is happening. Any help would be really appreciated, thank you.
If this line logs:
io.write(" First for y ",y,"\n")
and this line does not log:
io.write(" First for x ",x,"\n")
Then the problem is on one of these lines:
Array2D[y]={} --clearing the new array
for x = 1,14 do
for x... definitely works for me, so I'd suggest it's the Array2D line. There is nothing syntactically wrong with it, so it must be a runtime error. Runtime errors should be reported by Lua or the application it is embedded into. If they aren't and the function just "stops" then you are debugging blind, and you will waste a lot of time on problems like this.
The only error I can think might happen on that line would be if Array2D is not a table. Since you are trying to index it, it needs to be. Array2D isn't declared in your function, this is fine if it is a global variable that is already defined elsewhere. However if it is meant to be a local variable just for this function then you should add local Array2D = {} to it.
Without knowing what Array2D is, or what your actual error is even, it's hard to give a more accurate answer. If you really have no better method of finding out the problem than logging, this, just before the Array2D line, should test my hypothesis:
io.write("Array2D is: ", type(Array2D), "\n")
Looks like Array2D is not initialized (or not a table), so it craps on Array2D[y]={}.
You can use pcall to call a function and trap errors, like this:
local ok, msg = pcall(IATetris, pieza, rotacion, array)
if not ok then
print("ERROR:", msg)
end
Side note: you should be using the local keyword whenever possible to limit the scope of your variables.

Resources