What is a neat way to load and store a list of images by name in Haskell? - list

I want to load a list (or any data structure) of images using a bunch of hardcoded names and an existing function loadImage :: String -> IO Image.
In Lua, I would do the following:
imageNames = {"background", "gun", "man"}
images = {}
for i,v in ipairs(imageNames) do
images[v] = loadImage(v..".png")
end
And access them with images.background, images.man etc. How could I go about this in Haskell?

import Data.Map
imageNames :: [String]
imageNames = ["background", "gun", "man"]
images :: [IO (String, Image)]
images = [loadImage(name ++ ".png") >>= return . (,) name | name <- imageNames]
main = do
imgs <- sequence images
let imageMap = fromList imgs
return ()
imageMap is a Map from which you can access a image by its name : imageMap ! "gun"

Basically what Ankur said, I probably wouldn't have an explicit 'images' list and would probably use JuicyPixels to do the loading:
import Data.Map
import Codec.Picture
images :: [String]
images = ["background", "gun", "man"]
main = do
imgs <- mapM loadImage images
let imageMap = fromList (zip images imgs)
return ()
loadImage :: IO DynamicImage
loadImage = either id (error "Bad Image") `fmap` readImage

I'm a little late to the party, but here's another way to do it. It works on a slightly different principle than the other solutions, but the end result is the same.
import Data.Map (insert, empty)
import Data.List (foldl')
import Control.Applicative ((<$>))
import Control.Monad (forM)
imageNames = ["background", "gun", "man"]
images = foldl' (flip id) empty <$> forM imageNames (\name ->
insert name <$> loadImage (name ++ ".png")
)
What images does is that it builds a list of insert operations that are waiting to be performed on a Map. It then uses foldl' to thread a Map through the list of insert operations. As the fold goes along it uses the insert operations to build a larger and larger Map with the desired values. In other words, this does not build an intermediary [(String, Image)] which it then converts to a Map String Int.
The IO is carried all the way from loadImage to the outer function with <$> and sequence, giving the resulting type IO (Map String Image).
I think the other solutions are much easier to read (and probably a lot more efficient as well), so I recommend one of them. I just wanted to throw this out there.

Related

Haskell: how to make a list of files and a list of directories out of one common list

This is a newbie question. Suppose I want to separate a list of files and directories into a list of files and a list of directories:
getFilesAndDirs :: [FilePath] -> ([FilePath], [FilePath])
getFilesAndDirs paths =
let ...
in (dirs, files)
Probably this is a hopeless duplicate, I just miss the right keywords.
What is the right way to do (and call) this?
The files and the directories occur randomly.
The Data.List package has the partition :: (a -> Bool) -> [a] -> ([a],[a]) function which splits a list of as into a tuple of two lists of as based on a predicate.
The problem is however that when we check if a file is a directory, we probably will use isDirectory :: FilePath -> IO Bool so we can not directly use this as a predicate (since IO Bool is not equal to Bool).
We can write our own partitionM however, and use that one:
import Data.Bool(bool)
import Data.Foldable(foldrM)
partitionM :: (Foldable t, Monad m) => (a -> m Bool) -> t a -> m ([a], [a])
partitionM p = foldrM (selectM p) ([],[])
selectM :: Monad m => (a -> m Bool) -> a -> ([a], [a]) -> m ([a], [a])
selectM p x (ts,fs) = p x >>= return . bool (ts, x:fs) (x:ts,fs)
we can then use it like:
import System.Directory(isDirectory)
getFilesAndDirs :: [FilePath] -> IO ([FilePath], [FilePath])
getFilesAndDirs = partitionM isDirectory
Note that it is an IO ([FilePath], [FilePath]), since we need to perform I/O to check if a path is indeed a directory (and not a file).
You can use do notation to orchestrate the impure parts of your program, and then use the built-in (pure) functions like partition to do the actual work. Here's an example:
module Q47755054 (getFilesAndDirs) where
import Data.List (partition)
import Data.Bifunctor (bimap)
import System.Directory (doesDirectoryExist)
tagPath :: FilePath -> IO (FilePath, Bool)
tagPath path = do
isDirectory <- doesDirectoryExist path
return (path, isDirectory)
getFilesAndDirs :: [FilePath] -> IO ([FilePath], [FilePath])
getFilesAndDirs paths = do
taggedPaths <- mapM tagPath paths
return $ bimap (fmap fst) (fmap fst) $ partition snd taggedPaths
Notice that this uses the built-in mapM function to get an impure list of values (IO [(FilePath, Bool)]), but due to the do syntax and the <- binding, taggedPaths 'looks' like a pure value ([(FilePath, Bool)]), and therefore you can pass it to partition.
Notice, additionally, that tagPath is just a module-level helper function that isn't exported by the module.
module SeparateFiles where
import Data.String
import System.FilePath.Posix
type Path = FilePath
getFilesAndDirs :: Path -> [(Path,Path)]
getFilesAndDirs path = [splitFileName path]
I understand that you want to split your FilePath extracting into a file and directory. I provide you a very short example.

How to add tuples to list after reading from a text file in Haskell

I am trying to create a program in Haskell that reads text from a text file and adds them to a list.
My idea is:
type x = [(String, Integer)]
where the String is each word from the text and Integer is how many times that word occurs in the text. So I want to create a tuple of those values and add it to a list. I then want to print the contents of the list.
I know how to read a text file in Haskell, but am unsure as to what to do next. I am new to programming in Haskell and have predominantly been programming in Java which is very different.
EDIT:
This is what I have so far from the suggestions. I am able to write to an output text file with the text received from the file and make it lower case. The issues I am having is using the other functions because it says:
Test.hs:14:59: Not in scope: ‘group’
Here is the code:
import System.IO
import Data.Char(toLower)
main = do
contents <- readFile "testFile.txt"
let lowContents = map toLower contents
let outStr = countWords (lowContents)
let finalStr = sortOccurrences (outStr)
print outStr
-- Counts all the words
countWords :: String -> [(String, Int)]
countWords fileContents = countOccurrences (toWords fileContents)
-- Split words
toWords :: String -> [String]
toWords s = words s
-- Counts, how often each string in the given list appears
countOccurrences :: [String] -> [(String, Int)]
countOccurrences xs = map (\xs -> (head xs, length xs)) . group . sortOccurrences xs
-- Sort list in order of occurrences.
sortOccurrences :: [(String, Int)] -> [(String, Int)]
sortOccurrences sort = sortBy sort (comparing snd)
Please can anyone help me with this.
Haskell features a fairly expressive type system (much more so than Java) so it's a good idea to consider this issue purely in terms of types, in a top-down fashion. You mentioned that you already know how read a text file in Haskell, so I'll assume you know how to get a String which holds the file contents.
The function you'd like to define is something like this. For now, we'll set the definition to undefined such that the code typechecks (but yields an exception at runtime):
countWords :: String -> [(String, Int)]
countWords fileContents = undefined
Your function maps a String (the file contents) to a list of tuples, each of which associating some word with the count how often that word appeared in the input. This sounds like one part of the solution will be a function which can split a string into a list of words such that you can then process that to count the words. I.e. you'll want something like this:
-- Splits a string into a list of words
toWords :: String -> [String]
toWords s = undefined
-- Counts, how often each string in the given list appears
countOccurrences :: [String] -> [(String, Int)]
countOccurrences xs = undefined
With these at hand, you can actually define the original function:
countWords :: String -> [(String, Int)]
countWords fileContents = countOccurrences (toWords fileContents)
You now nicely decomposed the problem into two sub-problems.
Another nice aspect of this type-driven programm is that Hoogle can be told to go look for functions for a given type. For instance, consider the type of the toWords function we sketched earlier:
toWords :: String -> [String]
toWords s = undefined
Feeding this to Hoogle reveals a nice function: words which seems to do just what we want! So we can define
toWords :: String -> [String]
toWords s = words s
The only thing missing is coming up with an appropriate definition for countOccurrences. Alas, searching for this type on Hoogle doesn't show any ready-made solutions. However, there are three functions which will be useful for coming up with our own definition: sort, group and map:
The sort function does, what the name suggests: it sorts a list of things:
λ: sort [1,1,1,2,2,1,1,3,3]
[1,1,1,1,1,2,2,3,3]
The group function groups consecutive(!) equal elements, yielding a list of lists. E.g.
λ: group [1,1,1,1,1,2,2,3,3]
[[1,1,1,1,1],[2,2],[3,3]]
The map function can be used to turn the list of lists produced by group into a list of tuples, giving the length of each group:
λ: map (\xs -> (head xs, length xs)) [[1,1,1,1,1],[2,2],[3,3]]
[(1,5),(2,2),(3,2)]
Composing these three functions allows you to define
countOccurrences :: [String] -> [(String, Int)]
countOccurrences xs = map (\xs -> (head xs, length xs)) . group . sort $ xs
Now you have all the pieces in place. Your countWords is defined in terms to toWords and countOccurrences, each of which having a proper definition.
The nice thing about this type-driven approach is that writing down the funciton signatures will help both your thinking as well as the compiler (catching you when you violate assumptions). You also, automatically, decompose the problem into smaller problems, each of which you can test independently in ghci.
Data.Map is the easiest way to do this.
import qualified Data.Map as M
-- assuming you already have your list of words:
listOfWords :: [String]
-- you can generate your list of tuples with this
listOfTuples :: [(String, Integer)]
listOfTuples = M.toList . M.fromListWith (+) $ zip listOfWords (repeat 1)

Yesod: Is it possible to to iterate a haskell list in Julius?

I have a list of coordinates that I need to put on map. Is it possible in julius to iterate the list ? Right now I am creating an hidden table in hamlet and accessing that table in julius which does not seem to be an ideal solution.
Could some one point to a better solution ? Thanks.
edit: Passing a JSON string for the list (which can be read by julius) seems to solve my problem.
As far as I know, you can't directly iterate over a list in julius. However, you can use the Monoid instance for the Javascript type to accomplish a similar effect. For example:
import Text.Julius
import Data.Monoid
rows :: [Int] -> t -> Javascript
rows xs = mconcat $ map row xs
where
row x = [julius|v[#{show x}] = #{show x};
|]
Then you can use rows xs wherever you'd normally put a julius block. For example, in ghci:
> renderJavascript $ rows [1..5] ()
"v[1] = 1;\nv[2] = 2;\nv[3] = 3;\nv[4] = 4;\nv[5] = 5;\n"

Haskell: Scan Through a List and Apply A Different Function for Each Element

I need to scan through a document and accumulate the output of different functions for each string in the file. The function run on any given line of the file depends on what is in that line.
I could do this very inefficiently by making a complete pass through the file for every list I wanted to collect. Example pseudo-code:
at :: B.ByteString -> Maybe Atom
at line
| line == ATOM record = do stuff to return Just Atom
| otherwise = Nothing
ot :: B.ByteString -> Maybe Sheet
ot line
| line == SHEET record = do other stuff to return Just Sheet
| otherwise = Nothing
Then, I would map each of these functions over the entire list of lines in the file to get a complete list of Atoms and Sheets:
mapper :: [B.ByteString] -> IO ()
mapper lines = do
let atoms = mapMaybe at lines
let sheets = mapMaybe to lines
-- Do stuff with my atoms and sheets
However, this is inefficient because I am maping through the entire list of strings for every list I am trying to create. Instead, I want to map through the list of line strings only once, identify each line as I am moving through it, and then apply the appropriate function and store these values in different lists.
My C mentality wants to do this (pseudo code):
mapper' :: [B.ByteString] -> IO ()
mapper' lines = do
let atoms = []
let sheets = []
for line in lines:
| line == ATOM record = (atoms = atoms ++ at line)
| line == SHEET record = (sheets = sheets ++ ot line)
-- Now 'atoms' is a complete list of all the ATOM records
-- and 'sheets' is a complete list of all the SHEET records
What is the Haskell way of doing this? I simply can't get my functional-programming mindset to come up with a solution.
First of all, I think that the answers others have supplied will work at least 95% of the time. It's always good practice to code for the problem at hand by using appropriate data types (or tuples in some cases). However, sometimes you really don't know in advance what you're looking for in the list, and in these cases trying to enumerate all possibilities is difficult/time-consuming/error-prone. Or, you're writing multiple variants of the same sort of thing (manually inlining multiple folds into one) and you'd like to capture the abstraction.
Fortunately, there are a few techniques that can help.
The framework solution
(somewhat self-evangelizing)
First, the various "iteratee/enumerator" packages often provide functions to deal with this sort of problem. I'm most familiar with iteratee, which would let you do the following:
import Data.Iteratee as I
import Data.Iteratee.Char
import Data.Maybe
-- first, you'll need some way to process the Atoms/Sheets/etc. you're getting
-- if you want to just return them as a list, you can use the built-in
-- stream2list function
-- next, create stream transformers
-- given at :: B.ByteString -> Maybe Atom
-- create a stream transformer from ByteString lines to Atoms
atIter :: Enumeratee [B.ByteString] [Atom] m a
atIter = I.mapChunks (catMaybes . map at)
otIter :: Enumeratee [B.ByteString] [Sheet] m a
otIter = I.mapChunks (catMaybes . map ot)
-- finally, combine multiple processors into one
-- if you have more than one processor, you can use zip3, zip4, etc.
procFile :: Iteratee [B.ByteString] m ([Atom],[Sheet])
procFile = I.zip (atIter =$ stream2list) (otIter =$ stream2list)
-- and run it on some data
runner :: FilePath -> IO ([Atom],[Sheet])
runner filename = do
resultIter <- enumFile defaultBufSize filename $= enumLinesBS $ procFile
run resultIter
One benefit this gives you is extra composability. You can create transformers as you like, and just combine them with zip. You can even run the consumers in parallel if you like (although only if you're working in the IO monad, and probably not worth it unless the consumers do a lot of work) by changing to this:
import Data.Iteratee.Parallel
parProcFile = I.zip (parI $ atIter =$ stream2list) (parI $ otIter =$ stream2list)
The result of doing so isn't the same as a single for-loop - this will still perform multiple traversals of the data. However, the traversal pattern has changed. This will load a certain amount of data at once (defaultBufSize bytes) and traverse that chunk multiple times, storing partial results as necessary. After a chunk has been entirely consumed, the next chunk is loaded and the old one can be garbage collected.
Hopefully this will demonstrate the difference:
Data.List.zip:
x1 x2 x3 .. x_n
x1 x2 x3 .. x_n
Data.Iteratee.zip:
x1 x2 x3 x4 x_n-1 x_n
x1 x2 x3 x4 x_n-1 x_n
If you're doing enough work that parallelism makes sense this isn't a problem at all. Due to memory locality, the performance is much better than multiple traversals over the entire input as Data.List.zip would make.
The beautiful solution
If a single-traversal solution really does make the most sense, you might be interested in Max Rabkin's Beautiful Folding post, and Conal Elliott's followup work (this too). The essential idea is that you can create data structures to represent folds and zips, and combining these lets you create a new, combined fold/zip function that only needs one traversal. It's maybe a little advanced for a Haskell beginner, but since you're thinking about the problem you may find it interesting or useful. Max's post is probably the best starting point.
I show a solution for two types of line, but it is easily extended to five types of line by using a five-tuple instead of a two-tuple.
import Data.Monoid
eachLine :: B.ByteString -> ([Atom], [Sheet])
eachLine bs | isAnAtom bs = ([ {- calculate an Atom -} ], [])
| isASheet bs = ([], [ {- calculate a Sheet -} ])
| otherwise = error "eachLine"
allLines :: [B.ByteString] -> ([Atom], [Sheet])
allLines bss = mconcat (map eachLine bss)
The magic is done by mconcat from Data.Monoid (included with GHC).
(On a point of style: personally I would define a Line type, a parseLine :: B.ByteString -> Line function and write eachLine bs = case parseLine bs of .... But this is peripheral to your question.)
It is a good idea to introduce a new ADT, e.g. "Summary" instead of tuples.
Then, since you want to accumulate the values of Summary you came make it an istance of Data.Monoid. Then you classify each of your lines with the help of classifier functions (e.g. isAtom, isSheet, etc.) and concatenate them together using Monoid's mconcat function (as suggested by #dave4420).
Here is the code (it uses String instead of ByteString, but it is quite easy to change):
module Classifier where
import Data.List
import Data.Monoid
data Summary = Summary
{ atoms :: [String]
, sheets :: [String]
, digits :: [String]
} deriving (Show)
instance Monoid Summary where
mempty = Summary [] [] []
Summary as1 ss1 ds1 `mappend` Summary as2 ss2 ds2 =
Summary (as1 `mappend` as2)
(ss1 `mappend` ss2)
(ds1 `mappend` ds2)
classify :: [String] -> Summary
classify = mconcat . map classifyLine
classifyLine :: String -> Summary
classifyLine line
| isAtom line = Summary [line] [] [] -- or "mempty { atoms = [line] }"
| isSheet line = Summary [] [line] []
| isDigit line = Summary [] [] [line]
| otherwise = mempty -- or "error" if you need this
isAtom, isSheet, isDigit :: String -> Bool
isAtom = isPrefixOf "atom"
isSheet = isPrefixOf "sheet"
isDigit = isPrefixOf "digits"
input :: [String]
input = ["atom1", "sheet1", "sheet2", "digits1"]
test :: Summary
test = classify input
If you have only 2 alternatives, using Either might be a good idea. In that case combine your functions, map the list, and use lefts and rights to get the results:
import Data.Either
-- first sample function, returning String
f1 x = show $ x `div` 2
-- second sample function, returning Int
f2 x = 3*x+1
-- combined function returning Either String Int
hotpo x = if even x then Left (f1 x) else Right (f2 x)
xs = map hotpo [1..10]
-- [Right 4,Left "1",Right 10,Left "2",Right 16,Left "3",Right 22,Left "4",Right 28,Left "5"]
lefts xs
-- ["1","2","3","4","5"]
rights xs
-- [4,10,16,22,28]

haskell list of tuples, with unique tuples

I come from a Python and Java background so Haskell is quite different for me. I'm trying little activities to learn but I am stuck on this .
I have an ordered list of tuples, [(name, studentNumber)], and I want to filter this list so that each student and each studentNumber appears only once. Since the tuples are ordered, I want to keep the first instance of a name or studentNumber and remove any others that may show up.
I tried doing a list comphrenshion, but I'm not sure how to check if a name or number has already been added to the list.
It sounds as if you'd want (as a first, inefficient approximation) something like this:
import Data.List (nubBy)
import Data.Function (on)
filt = nubBy ((==) `on` snd) . nubBy ((==) `on` fst)
The first call to nubBy will result in a list in which each name appears only once, and that will then be passed to the second, resulting in a list in which each number appears only once.
Just using nub will result in a list in which each (name,number) pair occurs only once; there might still be repetitions of names with different numbers and numbers with different names.
(Of course something custom with an accumulator would be faster.)
You can spy on Data.List sources and write your extended nub function:
type Student = (Name, Number)
type Name = String
type Number = Int
unique :: [Student] -> [Student]
unique = go [] []
where
go unames unumbers (s#(name, number):ss)
| name `elem` unames || number `elem` unumbers = go unames unumbers ss
| otherwise = s : go (name:unames) (number:unumbers) ss
go _ _ [] = []
Should do what you want.
To unique-ify a list there's always the nub function from the prelude, I think that should do exactly what you need!