Sum the filesizes in a directory - haskell

I'm having trouble wrapping my head around how to accomplish this. I'm relatively new to working with monads/IO, so excuse me if I'm missing something obvious. I searched google for a while and came up with nothing, and nothing I've read is making me figure out how to do this.
Here is what I have now:
import System.Path.Glob (glob)
import System.Posix.Files (fileSize, getFileStatus)
dir = "/usr/bin/"
lof = do files <- (glob (dir++"*"))
(mapM_ fileS files)
fileS file = do fs <- getFileStatus file
print (fileSize fs)
As you can see, this gets the sizes and prints them out, but I'm stuck on how to actually sum them.

You're almost there. You can have fileS return the file size instead of printing it:
return (fileSize fs)
Then, instead of mapM_ing (which throws away the result), do a mapM (which returns the list of results):
sizes <- mapM fileS files
Now sizes is a list of numbers corresponding to the sizes. summing them should be easy :-)
To deepen your understanding of this example (and practice good habits), try to write type signatures for your functions. Consult ghci with :t for help.

Related

Xmonad: Prompt with output of shell commands as completion options

When I try to put the output of a shell command into an xmonad prompt as a completion option, i.e. as something that can be chosen via the prompt, I keep running compile errors, no matter what I try.
After initially getting a basic custom prompt to work, the following sanity check:
mkXPrompt TestPrompt config (mkComplFunFromList config ["a", compltest) testFun
compltest = do
output <- "b"
return output
This may not be terribly idiomatic Haskell, but it works as expected, it compiles and "a" as well as "b" are available options in the prompt. But I just can't get compltest to return the output of a shell command.
I have extensively looked at the source of all instances of xmonad prompt I could find in xmonad.contrib, and I have also checked here and on other websites for questions regarding similar issues, found a few and read them thoroughly.
The problem is that in all these cases, people are either doing something FAR more complex than what I'm attempting to do, or something that is simply very different. If I was better at Haskell I could probably adapt something for my needs, but so far I have spend several hours cobbling together functions and going from one compile error (usually type errors) to the next, no matter what I tried.
What I could so far gather is that I cannot "extract" a string out of an IO String for security reasons, and so should use liftIO in some way. I have also understood that some of the magic should happen in a do block, and that for Xmonad, runProcessWithInput is supposed to work somewhat better than readProcess. But practically applying this knowledge is a different matter.
Here is a tiny subset of the mass of functions I have tried so far, using the command "date" as an example (i.e. the output of the date command at the time of invoking the prompt should be a completion option in the prompt):
compltest = do
output <- liftIO $ putStrLn $ runProcessWithInput "date" [] ""
return output
compltest = do
output <- liftIO $ runProcessWithInput "date" [] ""
return output
compltest = io $ (runProcessWithInput "date" [] "" >>= readIO)
I guess bind your key to something like this:
do
output <- runProcessWithInput "date" [] ""
mkXPrompt TestPrompt config (mkComplFunFromList config [output]) testFun
Of course there are more interesting things to do with output than making it a singleton list; if f is your favorite String -> [String] function, then replace [output] with (f output) in the last line.

How find all the filenames when a list of file name fragments inputed using python glob?

I have a list of file name fragments, and I want to return a list of all the file names under a certain directory.
I wrote this code to tackle this problem, but it turns out that is a rather slow solution.
train_file_list = []
for p in patient_list[:n_train]:
file = glob(os.path.join("D:\preprocess_data\Positive", p + "*.npz"))
train_file_list.append(file)
Hopefully, I can rely on your talent to come up with a more efficient way to do this. Thanks!!!

Get elements of a list inside a list

When working with lists in Haskell, i can simply load my file into ghci and type head list or last list to get the information that I need. But if I have a list of lists, lets say: list = [[1,2,3],[4,5,6]], how can I get the first element (head) of the first list (in this case, 1), or the last element of the second list (in this case, 6), and so one?
If all you need is the first or last element, concat will flatten the list for you.
There is an indexing function (!!), so for your examples, head . (!!0) and last . (!!1) . If your question is more general, then please elaborate. Indexing is not great because it can throw errors if you attempt to index past the end of the list, so usually we try to work around that, eg. by saying "well I want to do the same thing to every element of the list so I don't really need the index" (map function) or "if I really do need the index then don't use it directly") (zip [0..], or use of eg. a record data type).
Also, Hoogle is your friend if you've not met it before. If you can break down your functions into simple ones you think might be standard, then search their type signatures, that's usually a good place to start. Hoogle [a] -> Int -> a even if you don't find exactly what you want, often if you find something similar and browse it's module or source code you can find something helpful.

"resource busy (file is locked)" error in Haskell

I'm very new to Haskell. In fact, I'm working through this section of this tutorial.
I came across this piece of code:
import System.IO
import Data.Char
main = do
contents <- readFile "girlfriend.txt"
writeFile "girlfriendcaps.txt" (map toUpper contents)
Which reads the contents of the file called "girlfriend.txt" and writes the upper-cased version of the file to a new file called "girlfriendcaps.txt".
So, I wanted to modify the code a bit to take the name of the file to act on. I changed the code to this:
import System.IO
import Data.Char
main = do
path <- getLine
contents <- readFile path
writeFile path (map toUpper contents)
now, obviously the major difference here is that I'm reading from and writing to the same file. As I'm thinking about it now, this must be a lazy-evaluation thing, but i'm getting the "resource busy" error message. Correct me if I'm wrong, but I guess that readFile doesn't start reading the file until writeFile asks for the contents of it. And then writeFile tries to write to the file, but it must still have the file open because it's also asking for the contents. Am I close there?
So, the real question is: how do I read from and write to the same file in Haskell? It makes sense that it's more difficult, because you will write to a different file from the file you read from more often than not, but for my own edification, how would you read and write to the same file?
Indeed, this is a "lazy evaluation thing".
import System.IO
import Data.Char
main = do
path <- getLine
contents <- readFile path
writeFile path (map toUpper contents)
Remember that Haskell is primarily lazy in evaluation, and so is much of the IO subsystem. So when you call 'readFile' you begin streaming data in from the file. When you then immediately call "writeFile" you start streaming bytes back to the same file
This would be an error (i.e. destroy your data), so Haskell locks the resource until it is fully evaluated, and you get a nice error message.
There are two solutions:
Don't destructively overwrite the file, instead, copy to a new file
Or, use strict IO
To use strict IO, the 'text' or 'strict' packages are recommended.
What you're looking for is how to open a file in ReadWriteMode.
fileHandle <- openFile "fileName.txt" ReadWriteMode
contents <- hGetContents fileHandle
There's trickier stuff for navigating forwards and backwards through the file.
See Working with files and handles from RWH, and Operations on Handles at the System.IO docs.
Depends on exactly what you are trying to do. As a rule, in any language, this is probably a bad design because if anything goes wrong either inside the program or outside (e.g user error) then you have destroyed your original data and cannot try again. It also requires that the entire file be held in memory, which is cool if its just a few bytes, but not so good when someone decides to run this on a really big file.
If you really want to do this then generate a temporary filename for the output, and then once you know that you have written to it successfully you can delete the original and rename the new one.

How do I rotate a JPEG image by 45° and save it back to disk in Haskell?

How do I rotate a JPEG image by 45° and save it back to disk?
As far as I know, there is no good image manipulation library for Haskell yet.
Better way
You can use hsmagick (bindings to libmagick) to manipulate images.
See TomMD's answer for an example.
Easy way
But if you want to do it from Haskell, this can do the trick (assuming that ImageMagick is available):
import System.Cmd (system)
import System.Environment (getArgs)
main = do
(original:rotated:_) <- getArgs
system $ "convert -rotate \"-45\" \"" ++ original ++ "\" \"" ++ rotated ++ "\""
Usage:
runghc rotate.hs original.jpg rotated45.jpg
Hard way
Or you can choose the hard way, and implement rotation algorithm yourself. To read and write almost all image formats in Haskell, you can use Codec.Image.DevIL library. If you do it, it would be kind of you to put this code on Hackage.
The GD library lets you do this, but the Haskell bindings ( http://hackage.haskell.org/package/gd ) don't include the appropriate function at the moment. One also could either make a feature request to the maintainer, or simply patch it and send it upstream. The Graphics.GD.Internal module (not exported) in fact already has a commented out binding to the appropriate function ( http://hackage.haskell.org/packages/archive/gd/3000.5.0/doc/html/src/Graphics-GD-Internal.html ), so it should be very simple, I imagine, to finish the job (and I'm sure, the work will be appreciated).
Look around on Hackage. I know Tim started working on bindings to libmagick, which wasn't enough to stop me from dropping down to generating script-fu for GIMP when I needed image manipulation, but it's enough for you if you're just doing simple things like rotation:
liftM (rotateImage 45) (readImage file) >>= writeImage file2
I see Cale also has an ImLib that appears more feature complete:
loadImageImmediately file >>= contextSetImage >>
createRotatedImage 45 >>= contextSetImage >> saveImage file2
As I said, look around and let us know!

Resources