Reputation: 97
I have a program that I've written in Haskell, and everything except the IO is working. The IO is meant to do the following: - Take in a number from the user - If this number is positive, read that many lines into a list, then take the number and created list and pass it to a function which will return the output - If this number is negative instead, only read the next line, and take the number and that line and pass it to a function which returns other output
I've been using "interpret (unlines . map program . lines)" bit of code for testing purposes, but I'm not sure how to make it handle multiple line input (especially when the number of lines isn't constant)
I would appreciate any help
Ahh yes, and the program loops
More details: The program itself handles quadtrees. Input can be along the lines of this: 8 00000000 00111111 00001111 00001111 00011111 00111100 00111000 In which case the program sees the 8, the size of the picture, and builds its corresponding quadtree. The output is rather convoluted, but basically it turns it into a text representation of the quadtree's structure.
Current program:
module Main where
main = interact (unlines . map program . lines) -- the IO here is bologna, as it doesn't do anything with the user input
--turns ones and zeros into easier to distinguish characters
replace 0 = '.'
replace 1 = '*'
program x = display (toArray 8 (t2)) -- just a test case to see if the important functions work, as well as a placeholder for real IO, hopefully
data Quadtree a = Tip | Node a (Quadtree a) (Quadtree a) (Quadtree a) (Quadtree a) -- the quadtree datastructure
leaf x = Node x Tip Tip Tip Tip -- saves some typing
-- this function takes a quadtree and returns a 2-dimensional list of binary digits to draw the picture
toArray a (Node x Tip Tip Tip Tip) = replicate a (replicate a x)
toArray a (Node x b c d e) = (zipWith (++) (toArray (div a 2) b) (toArray (div a 2) c)) ++ (zipWith (++) (toArray (div a 2) d) (toArray (div a 2) e))
display x = unlines (map (map replace) x) -- gives a printable form of the two dimensional array
-- function that turns a number from base five
basefive x
| x < 5 = x
| x >= 5 = basefive (div x 5) * 10 + (mod x 5)
-- inserts into quadtree
insert [] (Node 0 Tip Tip Tip Tip) = Node 1 Tip Tip Tip Tip
insert (x:xs) (Node 0 Tip Tip Tip Tip)
| x == '1' = Node 2 (insert xs (leaf 0)) (leaf 0) (leaf 0) (leaf 0)
| x == '2' = Node 2 (leaf 0) (insert xs (leaf 0)) (leaf 0) (leaf 0)
| x == '3' = Node 2 (leaf 0) (leaf 0) (insert xs (leaf 0)) (leaf 0)
| x == '4' = Node 2 (leaf 0) (leaf 0) (leaf 0) (insert xs (leaf 0))
insert (x:xs) (Node a b c d e)
| x == '1' = Node a (insert xs b) c d e
| x == '2' = Node a b (insert xs c) d e
| x == '3' = Node a b c (insert xs d) e
| x == '4' = Node a b c d (insert xs e)
-- builds quadtree from scratch
insertall [] x = x
insertall (x:xs) y = insert x (insertall xs y)
s1 = "9 14 17 22 23 44 63 69 88 94 113" -- the example quadtree "path"; it represents the structure
s2 = ["00000000","00000000","00001111","00001111","00011111","00111111","00111100","00111000"] -- this represents the image
-- function which splits a list in half
split :: [a] -> ([a],[a])
split xs = go xs xs where
go (x:xs) (_:_:zs) = (x:us,vs) where (us,vs)=go xs zs
go xs _ = ([],xs)
quarter a b c = ((a . split) (map (b . split) c)) -- function which quarters a 2 dimensional list
-- function which takes a 2 dimensional array and returns its tree
toTree a x
| x == replicate a (replicate a '1') = (leaf 1)
| x == replicate a (replicate a '0') = (leaf 0)
| otherwise = Node 2 (toTree (div a 2) (quarter fst fst x)) (toTree (div a 2) (quarter fst snd x)) (toTree (div a 2) (quarter snd fst x)) (toTree (div a 2) (quarter snd snd x))
t2 = toTree 8 s2
Both s1 and s2 are sample user inputs; the random eights thrown around is the size of the quadtree image, which is supposed to also be supplied by the user
Upvotes: 1
Views: 1311
Reputation: 38893
So you really have a spec for a function:
Take in a number from the user - If this number is positive, read that many lines into a list, then take the number and created list and pass it to a function which will return the output - If this number is negative instead, only read the next line, and take the number and that line and pass it to a function which returns other output.
We can just write that function straightforwardly.
interactiveFun f g = do
let readInt :: String -> Int
readInt = read
x <- fmap readInt getLine
if x > 0
then print . f . map readInt =<< replicateM x getLine
else print . g x . readInt =<< getLine
Edit: <$>
is the same an infix fmap
, and comes from Control.Applicative. Its idiomatic Haskell, but I've edited it out for simplicity. replicateM
comes from Control.Monad. You should import it and use it -- many many everyday Haskell functions come from base libraries other than the Prelude
. All those base libraries are part of the standard, are portable, are useful, and should be used liberally.
Upvotes: 4