How to go through Effect (Array String) in purescript - purescript

I'm learning purescript and trying to log a directory content.
module Main where
import Prelude
import Data.Traversable (traverse)
import Effect (Effect)
import Effect.Console (log)
import Node.FS.Sync (readdir)
fnames = readdir "."
main = do
travere (\a -> log $ show a) fnames
I want to get folder entries printed in console output.
I can not get rid of (or pass through) the Effect which I get from Node.FS.Sync (readdir) (I get Effect (Array String)). And traverse or log or show can not work with Effect in front of Array String.
I get No type class instance was found for Data.Traversable.Traversable Effect.

Effect is a program, not a value. Effect (Array String) is a program that, when executed, will produce an Array String. You cannot get the Array String out of that program without executing it.
One way to execute this program is to make it part of a larger program, such as, for example, your main program. Like this:
main = do
ns <- fnames
traverse (\a -> log $ show a) ns
Of course, there is really no need to put it in a global variable fnames before making it part of the main program. You can include readdir "." directly:
main = do
ns <- readdir "."
traverse (\a -> log $ show a) ns

Related

splitting by dash in scala and selecting second one

We have a csv file having a column(name:Host) that has data like mb-web-scp-01, kl-mem-cpp-01 .
Having split by dash, I need to make a new column(name: Host2) having second one (web, mem from the above data)
import scala.io.Source._
If you want to handle errors as options, you can do this (output from Ammonite REPL):
# "mb-web-scp-01".split("-").drop(1).headOption
res1: Option[String] = Some(web)

CoffeeScript: calculate parse tree (like coffee -n) in a program

Is there a way to compute the CoffeeScript parse tree of a program (provided as a string) inside CoffeeScript without calling an external program?
For example, let's say I have a string 'square=(n)->n*n' inside a CoffeeScript program. I want to get the same output as storing this string in a file square.coffee and calling on the command line coffee -n square.coffee --- but without creating another process:
Block
Assign
Value "square"
Code
Param "n"
Block
Op *
Value "n"
Value "n"
Please, provide with your solution a link to documentation how to interpret the resulting data structure.
Just look in the source: the -n flag invokes (require 'coffee-script).nodes. The result is a syntax tree which corresponds to grammar.coffee and would be interpreted with nodes.coffee.
So this:
(require 'coffee-script').nodes 'square = (n)->n*n'
Will give you a syntax tree. Before you print it, you could use its toString method to get the same output as the coffee CLI.
For the filesystem operations, just use node's readFile or readFileSync from the fs library:
{readFileSync} = require 'fs'
{nodes} = require 'coffee-script'
nodes readFileSync('squares.coffee').toString()

.. automatically completes module path after import. MyMo.. works the same as MyModule. by autocomplete, ends with MyMo..:ok

Adding an extra dot allows modules to "autocomplete".
"My" code:
defmodule Rec do
def msgurr(text, n) when n <= 1 do
IO.puts text
end
def msgurr(text, n) do
IO.puts text
msgurr(text, n - 1)
end
end
When I reference it, as follows:
iex(6)> R..print_multiple_times("blah", 5)
blah
blah
blah
blah
blah
R..:ok
iex(7)> E..print_multiple_times("hello", 3)
hello
hello
hello
E..:ok
However, the following import command, with a call similar to the online documentation, does not work:
iex(8)> ..msgurr("Hello!", 3)
** (SyntaxError) iex:8: syntax error before: '..'
Why is this?
How does this sort of auto-completing import statement work in Elixir?
Is there any easy documentation for this?
I read through this question:
How do you create and load modules dynamically at runtime in Elixir, or Erlang?
However, it doesn't seem to say much about this little ".." thing for importing.
I haven't tested it out in an actual script, just the iex interpreter.
The extra dot is actually creating a range, so IEx will be smart enough to autocomplete to any imported function.
This is calling function foo in R:
R.foo
This is creating a range with R on the left side and whatever is foo on the right side:
R..foo
You don't need .. to autocomplete. Just hit tab on whatever expression:
is_at<TAB>
should autocomplete to is_atom.

Create .nfo-files recursively

I have a collection of concert-media (audio and video). They're all organised using the same pattern:
./ARTISTNAME/[YYYY-MM-DD] VENUE, CITY
Basically I want to write a script which goes through the folders, looks for the [YYYY-MM-DD]-folders and get the information regarding artist (one folder level above), date, venue and location (using the name of the folder it just found) and writing the information into a .nfo-file which it saves into the found folder.
I already did quite a research on this topic, found a similar script but I am stuck because it searches files instead of folders:
#!/bin/bash
find . -path "*[????-??-??]*" | while read folder; do # the script is supposed to look for the concert-folders
-> band_name=`echo $file_name | sed 's/ *-.*$//'` # Get rid of song name
-> band_name=`echo $band_name | sed 's/^.*\///'` # Get rid of file path
-> song_name=`echo $file_name | sed 's/^.*- *//'` # Get rid of band name
-> song_name=`echo $song_name | sed 's/.avi//'` # Get rid of file extension
-> new_file_name=`echo $file_name | sed 's/.avi/.nfo/'` # Make new filename
-> echo "Making $new_file_name..."
echo -en "<musicvideo>\n<venue>$venue_name</venue>\n<city>$city_name</city><date>$date>\date>\n<artist>$band_name</artist>\n</musicvideo>\n" > "$new_file_name"
done
After changing the first part of the script (making it look for the folders with "[YYYY-MM-DD]") I understand that the second part of the script allocates the "tags" (such as artist, date, location, etc.). But I don't know how to make the script take the tags from folder names. Basically help is needed after the "->".
At the last part of the script it is supposed to write the collected information for this folder into a .nfo-file (e.g. FOLDERNAME.nfo).
Here is a simple Python example to get you started. If you want to port it to shell you can.
First, my setup:
test
test/BOB
test/BOB/[3011-01-01] Lollapalooza 213, Saturn Base 5
test/THE WHO
test/THE WHO/[1969-08-17] Woodstock, Woodstock
The code:
#!/usr/bin/env python
import os
import os.path
import re
import sys
def handle_concert(dirname, artist, date, venue, city):
"""Create a NFO file in the directory."""
# the {} are replaced by each argument in turn, like printf()
# Using a triple quote is a lot like a here document in shell, i.e.
# cat <EOF
# foo
# EOF
nfo_data = """<musicvideo>
<venue>{}</venue>
<city>{}</city>
<date>{}</date>
<artist>{}</artist>
</musicvideo>
""".format(venue, city, date, artist)
nfo_file = "[{}] {}, {}.nfo".format(date, venue, city)
# when the with statement is done the file is closed and fully
# written.
with open(os.path.join(dirname, nfo_file), "w") as fp:
fp.write(nfo_data)
# This is a regular expression which matches:
# */FOO/[YYYY-MM-DD] VENUE, CITY
# Where possible, white space is left intact
concert_re = re.compile(r'.*/(?P<artist>.+)/\[(?P<date>\d{4}-\d{2}-\d{2})\]\s+(?P<venue>.+),\s+(?P<city>.+)')
def handle_artist(dirname):
"""Found an ARTIST directory. Look for concerts.
If a subdirectory is found, see if it matches a concert.
When a concert is found, handle it.
"""
for i in os.listdir(dirname):
subdir = os.path.join(dirname, i)
m = concert_re.match(subdir)
if m:
print subdir # to watch the progress
handle_concert(subdir, m.group("artist"), m.group("date"),
m.group("venue"), m.group("city"))
def walk_collection(start_dir):
"""Examine contents of start_dir.
If a directory is found, assume it is an ARTIST.
"""
for i in os.listdir(start_dir):
# os.path.join ensures paths are right regardless of OS
dirname = os.path.join(start_dir, i)
if os.path.isdir(dirname):
print dirname # to watch the progress
handle_artist(dirname)
if __name__ == "__main__":
collection_dir = sys.argv[1] # equiv of $1
walk_collection(collection_dir)
How to run it:
$ nfo-creator.py /path/to/your/collection
The results:
<musicvideo>
<venue>Woodstock</venue>
<city>Woodstock</city>
<date>1969-08-17</date>
<artist>THE WHO</artist>
</musicvideo>
and
<musicvideo>
<venue>Lollapalooza 213</venue>
<city>Saturn Base 5</city>
<date>3011-01-01</date>
<artist>BOB</artist>
</musicvideo>
You can add more handle_ functions to handle differing formats. Just define a new regular expression and a handler for it. I kept this really simple for learning purposes with plenty of shell oriented comments.
This could totally be done in the shell. But writing this Python code was way easier and allows for more growth in the future.
Enjoy, and feel free to ask questions.

A scala program much slower than the corresponding python script

I have written a short Scala program to read a large file, process it and store the result in another file. The file contains about 60000 lines of numbers, and I need to extract from each third line only the first number. Eventually I save those numbers to a different file. Although numbers, I treat them as strings all along the way.
Here is the Scala code:
import scala.io.Source
import java.io.BufferedWriter
import java.io.FileWriter
object Analyze {
def main(args: Array[String]) {
val fname = "input.txt"
val counters = Source.fromFile(fname).mkString.split("\\n").grouped(3)
.map(_(2).split("\\s+")(0))
val f = new BufferedWriter(new FileWriter("output1.txt"))
f.write(counters.reduceLeft(_ + "\n" + _))
f.close()
}
}
I like very much the Scala's capability of powerful one liners. The one-liner in the above code reads the entire text from the file, splits it into lines, groups the lines to groups of 3 lines, and then takes from each group the third line, splits it and takes the first number.
Here is the equivalient python script:
fname = 'input.txt'
with file(fname) as f:
lines = f.read().splitlines()
linegroups = [lines[i:i+3] for i in range(0, len(lines), 3)]
nums = [linegroup[2].split()[0] for linegroup in linegroups]
with file('output2.txt', 'w') as f:
f.write('\n'.join(nums))
Python is not capable of such one liners. In the above script the first line of code reads the file into a list of lines, the next one groups the lines into groups of 3, and the next one creates a list consisting of the first number of every last line of each group. It's very similar to the Scala code, only it runs much much faster.
The python script runs in a fraction of a second on my laptop, while the Scala program runs for 15 seconds! I commented out the code that saves the result to the file, and the duration fell to 5 seconds, which is still way too slow. Also I don't understand why it takes so long to save the numbers to the file. When I dealt with larger files, the python script ran for a few seconds, while the Scala program running time was in order of minutes, which I couldn't use to analyze my files.
I'll appreciate you advice for this issue.
Thanks
I took the liberty of cleaning up the code, this should run more efficiently by avoiding the initial mkString, not needing a regex to perform the whitespace split, and not pre-aggregating the results before writing them out. I also used methods that are better self-documenting:
val fname = "input.txt"
val lines = (Source fromFile fname).getLines
val counters =
(lines grouped 3 withPartial false) map { _.last takeWhile (!_.isWhitespace) }
val f = new BufferedWriter(new FileWriter("output1.txt"))
f.write(counters mkString "\n")
f.close()
Warning, untested code
This is largely irrelevant though, depending on how you're profiling. If you're including the JVM startup time in your metrics, then all bets are off - no amount of code optimisation could help you there.
I'd normally also suggest pre-warming the JVM by running the routine a few hundred times before you time it, but this isn't so practical in the face of file I/O.
I timed the version provided by Kevin with minor edits (removed withPartial since the python version doesn't handle padding either):
import scala.io.Source
import java.io.BufferedWriter
import java.io.FileWriter
object A extends App {
val fname = "input.txt"
val lines = (Source fromFile fname).getLines
val counters =
(lines grouped 3) map { _.last takeWhile (!_.isWhitespace) }
val f = new BufferedWriter(new FileWriter("output1.txt"))
f.write(counters mkString "\n")
f.close()
}
With 60,000 lines here are the timing:
$ time scala -cp classes A
real 0m2.823s
$ time /usr/bin/python A.py
real 0m0.437s
With 900,000 lines:
$ time scala -cp classes A
real 0m5.226s
$ time /usr/bin/python A.py
real 0m3.319s
With 2,700,000 lines:
$ time scala -cp classes A
real 0m9.516s
$ time /usr/bin/python A.py
real 0m10.635s
The scala version outperforms the python version after that. So it seems some of the long timing is due to JVM initialization and JIT compilation time.
In addition to #notan3xit's answer, you could also write counters to files without concatenating them first:
val f = new BufferedWriter(new FileWriter("output1.txt"))
f.write(counters.head.toString)
counters.tail.foreach(c => f.write("\n" + c.toString))
f.close()
Though you could do the same in Python...
Try this code for write to file:
val f = new java.io.PrintWriter(new java.io.File("output1.txt"))
f.write(counters.reduce(_ + "\n" + _))
f.close()
Much faster .