I would like to print some rectangles one by one in a terminal like that:
4 5 7 8
2 5
3 : bool 6 : int
Which represents that, given an array a, the zone from a([2,3], [4,5]) is bool and the zone from a([5,6], [7,8]) is int.
So the key is to print a block of data in several rows, instead of 1 row as default. Does anyone know how to realize that in Ocaml?
Thank you very much!
Basically, there are two approaches possible:
accumulate your two-dimensional output and use a specialized print function which rearranges the strings in a way you wish
print to a medium with 2D capabilities like terminal or GUI element (to play with terminal screen, one can use a binding to ncurses)
The first approach is more universal and remains functional in spirit. For example:
let item1 =
[" 4 5 "
;"2 "
;"3 : bool "
]
let item2 =
[" 7 8 "
;"5 "
;"6 : int "
]
let transpose ll =
let rec pick_one ll =
match ll with
| [] -> []
| [] :: _ -> []
| _ ->
let tear (reaped, rest) l =
match l with
| [] -> assert false
| hd :: tl -> (hd :: reaped, tl :: rest)
in
let (reaped, rest) = List.fold_left tear ([], []) ll in
(reaped :: (pick_one rest))
in
pick_one ll
let multiline_print items =
let by_lines = transpose items in
let show_line line = List.iter print_string line; print_endline "" in
List.iter show_line by_lines
let _ = multiline_print [item1; item2]
Depending on your needs, you may build printf-like functionality around this.
You need to route through a "layout engine" the strings produced by the functions in your new Printf-like module.
Related
Hi Guys I am trying to check whether the length of a list is not equal to length of a list within a list using haskells length function and pattern matching
This is the function i have and its type:
func :: [String] -> [[String]] -> String
where the return string is either "Error different lengths found" OR
"Lengths are the same"
This is what i would input and the expected output see below:
["Planet", "City"] [["Jupiter", "Earth"], ["Berlin", "Madrid", "Krakow"] ]
Output should be "Error different lengths found" due to ["Berlin", "Madrid", "Krakow"] being of size 3 where as ["Planet", "City"] is of size 2
bit unsure how to do this and would appreciate any help!
Something like this would check it in linear time.
compLength :: [String] -> [[String]] -> String
compLength s = go (length s)
where go _ [] = "All Good! Hurray!"
go n (y:ys)
| n /= length y = "Error different lengths found" ++ " [" ++ unwords y ++ "]"
| otherwise = go n ys
I think this gives you the base and the necessary information to tailor the output to your exact needs.
You can write a helper function to check if two lists have the same length, so you can implement a function:
sameLength :: [a] -> [a] -> Bool
sameLength … = …
When you have implemented such function, it is only a matter to check if all sublists have the same length. We can do this with all :: Foldable f => (a -> Bool) -> f a -> Bool:
func :: [a] -> [[a]] -> Bool
func xs yss
| all (sameLength xs) yss = "Lengths are the same"
| otherwise = "Error different lengths found"
I've got a short question regarding something I want to do in Haskell.
What I basically aim to achieve is to make a list of integers from 1 to a specific value y. Like [1..y], and the print this list with spaces between each number
Let's say i have [1..8]
My desired output is ("_" represents spaces):
_1_2_3_4_5_6_7_8
I have played a little bit with different things but without any luck
This is basically what Iv' got so far
printLst :: [Int] -> String
printLst (x:xs) = " " ++ putStr (show x) >> printLst xs
I've been searching around the web to find any solution to this, but I have not found anything that helps me do this.
Help is greatly appreciated
First, define a function which converts an Int to a String, then prepends a space to the result.
\x -> ' ' : show x
Now map this over your list:
> map (\x -> ' ' : show x) [1..8]
[" 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"]
Now we just need to concatenate all the strings into one:
> concat (map (\x -> ' ' : show x) [1..8])
" 1 2 3 4 5 6 7 8"
This can be simplied using the concatMap function:
> concatMap (\x -> ' ':show x) [1..8]
" 1 2 3 4 5 6 7 8"
which forms the basis for the Monad instance for lists:
> [1..8] >>= (\x -> ' ' : show x)
" 1 2 3 4 5 6 7 8"
or even more briefly, using function composition
> [1..8] >>= (' ' :) . show
" 1 2 3 4 5 6 7 8"
Once you have the final string, now you can worry about printing it.
> putStrLn $ [1..8] >>= (' ' :) . show
1 2 3 4 5 6 7 8
Well you are confusing things here, first of all:
putStr :: String -> IO ()
And you are returning a String, so no need to use that. Also, you have no patter for [] and singleton list, you can add them to get a better output like this:
printLst :: [Int] -> String
printLst [] = ""
printLst [x] = (show x)
printLst (x:xs) = (show x) ++ " " ++ printLst xs
If you want to use IO () function, use it in the main function:
main = do
putStrLn (printLst [1..8])
This is a list processing problem. For an empty list, we can return the empty string, for a non-empty list, we can first yield a space, followed by the show of that item, and then recurse on the rest of that list, like:
prefixSpace :: Show a => [a] -> String
prefixSpace [] = ""
prefixSpace (x:xs) = ' ' : show x ++ prefixSpace xs
Or as a "fold" pattern:
prefixSpace :: Show a => [a] -> String
prefixSpace = foldr (\x -> ((' ' : show x) ++)) ""
This will not print the string. For that you need putStrLn :: String -> IO (), but as the signature indicates, if you putStrLn some_string, you work with an IO ().
I am very new to F# and functional programming in general, and would like to recursively create a function that takes a list, and doubles all elements.
This is what I used to search for a spacific element, but im not sure how exactly I can change it to do what I need.
let rec returnN n theList =
match n, theList with
| 0, (head::_) -> head
| _, (_::theList') -> returnN (n - 1) theList'
| _, [] -> invalidArg "n" "n is larger then list length"
let list1 = [5; 10; 15; 20; 50; 25; 30]
printfn "%d" (returnN 3 list1 )
Is there a way for me to augment this to do what I need to?
I would like to take you through the thinking process.
Step 1. I need a recursive function that takes a list and doubles all the elements:
So, let's implement this in a naive way:
let rec doubleAll list =
match list with
| [] -> []
| hd :: tl -> hd * 2 :: doubleAll tl
Hopefully this logic is quite simple:
If we have an empty list, we return another empty list.
If we have a list with at least one element, we double the element and then prepend that to the result of calling the doubleAll function on the tail of the list.
Step 2. Actually, there are two things going on here:
I want a function that lets me apply another function to each element of a list.
In this case, I want that function to be "multiply by 2".
So, now we have two functions, let's do a simple implementation like this:
let rec map f list =
match list with
| [] -> []
| hd :: tl -> f hd :: map f tl
let doubleAll list = map (fun x -> x * 2) list
Step 3. Actually, the idea of map is such a common one that it's already built into the F# standard library, see List.map
So, all we need to do is this:
let doubleAll list = List.map (fun x -> x * 2) list
I would like to build a string list by prompting the user for input. My end goal is to be able to parse a string list against a simple hash table using a simple routine.
`let list_find tbl ls =
List.iter (fun x ->
let mbr = if Hashtbl.mem tbl x then "aok" else "not found"
in
Printf.printf "%s %s\n" x mbr) ls ;;`
Building a string list is accomplished with the cons operator ::, but somehow I am not able to get the prompt to generate a string list. A simpe list function returns anything that is put into it as a list:
`let build_strlist x =
let rec aux x = match x with
| [] -> []
| hd :: tl -> hd :: aux tl
in
aux x ;;`
Thus far, I have been able to set the prompt, but building the string list did not go so well. I am inclined to think I should be using Buffer or Scanning.in_channel. This is what I have thus far:
`#load "unix.cma" ;;
let prompt () = Unix.isatty Unix.stdin && Unix.isatty Unix.stdout ;;
let build_strlist () =
let rec loop () =
let eof = ref false in
try
while not !eof do
if prompt () then print_endline "enter input ";
let line = read_line () in
if line = "-1" then eof := true
else
let rec build x = match x with
| [] -> []
| hd :: tl -> hd :: build tl
in
Printf.printf "you've entered %s\n" (List.iter (build line));
done
with End_of_file -> ()
in
loop () ;;`
I am getting an error the keyword "line" has the type string, but an expression was expected of type 'a list. Should I be building the string list using Buffer.create buf and then Buffer.add_string buf prepending [ followed by quotes " another " and a semicolon? This seems to be an overkill. Maybe I should just return a string list and ignore any attempts to "peek at what we have"? Printing will be done after checking the hash table.
I would like to have a prompt routine so that I can use ocaml for scripting and user interaction. I found some ideas on-line which allowed me to write the skeleton above.
I would probably break down the problem in several steps:
get the list of strings
process it (in your example, simply print it back)
1st step can be achieved with a recursive function as follow:
let build_strlist' () =
let rec loop l =
if prompt () then (
print_string "enter input: ";
match read_line () with
"-1" -> l
| s -> loop (s::l)
) else l
in loop [];;
See how that function loops on itself and build up the list l as it goes. As you mentioned in your comment, I dropped the imperative part of your code to keep the functional recursion only. You could have achieved the same by keeping instead the imperative part and leaving out the recursion, but recursion feels more natural to me, and if written correctly, leads to mostly the same machine code.
Once you have the list, simply apply a List.iter to it with the ad hoc printing function as you did in your original function.
This may be a silly question, but I'm very new to Haskell. (I just started using it a couple of hours ago actually.)
So my problem is that I have a list of 4 elements and I need to print two on one line and two on a new line.
Here's the list:
let list1 = ["#", "#", "#", "#"]
I need the output to look like this:
##
##
I know that i could use the following to print every element on a new line:
mapM_ putStrLn list1
but I'm not sure how to adapt this for only printing part of the list on a new line.
You want something like Data.Text.chunksOf for arbitrary lists, which I've never seen anywhere so I always reimplement it.
import Data.List (unfoldr)
-- This version ensures that the output consists of lists
-- of equal length. To do so, it trims the input.
chunksOf :: Int -> [a] -> [[a]]
chunksOf n = unfoldr (test . splitAt n) where
test (_, []) = Nothing
test x = Just x
Then we can take your [String] and turn it into [[String]], a list of lists each corresponding to String components of a line. We map concat over that list to merge up each line from its components, then use unlines to glue them all together.
grid :: Int -> [String] -> String
grid n = unlines . map concat . chunksOf n
Then we can print that string if desired
main :: IO ()
main = putStrLn $ grid 2 list1
Edit: apparently there is a chunksOf in a fairly popular library Data.List.Split. Their version is to my knowledge identical to mine, though it's implemented a little differently. Both of ours ought to satisfy
chunksOf n xs ++ chunksOf n ys == chunksOf n (xs ++ ys)
whenever length xs `mod` n == 0.
You can do:
mapM_ putStrLn [(take 2 list1), (drop 2 list1)]
where take and drop return lists with the expected number of elements. take 2 takes two elements and drop 2 drops the first two elements.
Looking at tel link Data.List.Split, another solution can be built on using chop.
Define as follow into the lib,
chop :: ([a] -> (b, [a])) -> [a] -> [b]
chop _ [] = []
chop f as = b : chop f as'
where (b, as') = f as
Then following's simeon advice we end with this one liner,
let fun n = mapM_ putStrLn . chop (splitAt n)
chop appears to be a nice function, enough to be mentioned here to illustrate an alternative solution. (unfoldr is great too).
Beginner attempt:
myOut :: [String] -> IO ()
myOut [] = putStr "\n"
myOut (x:xs) =
do if x=="#"
then putStrLn x
else putStr x
myOut xs
ghci>myOut ["#", "#", "#", "#"]
##
##
ghci>