-1

I have a function, where a string is printed out repeatedly by a specific number of times. However, if a negative number is given, the function should print out an empty list.

main = print (repeat (-1) "Hello World")

repeat 1 x = x

repeat n x

  | n < 0 = *???*

  | n > 0 = x ++ repeat (n-1) x

What do I have to do, so that the empty list is printed out in square brackets, instead of quotes?

ceppuiqmx
  • 13
  • 2

3 Answers3

2

Let's look at signature of repeat

repeat :: Int -> [a] -> [a]

And we wish to have "empty" case for n <= 0. We could use monoids:

import Data.Monoid

repeat :: Int -> [a] -> [a]
...
| n <= 0 = mempty

or write for lists:

| n <= 0 = []

Updated

If we wish to print [] for empty String, we must "extend" print function, like this:

print' [] = putStrLn "[]"
print' z  = print z
viorior
  • 1,783
  • 11
  • 16
1

It's not clear exactly what you are trying to do, and hence where the problem is, so here are a few possible explanations.

  1. You intend to build a string, as you are currently doing, but would like the empty string to print as '[]' rather than '""'.

As an example of this, consider: let test = if (True) then [] else ['a'] print test ""

If this is the problem, I don't know how to change the default behaviour. Your best way would be to avoid using 'print' and instead use a combination of 'putStrLn' and your own printing function:

myShow :: String -> String
myShow "" = "[]"
myShow a = a

main = putStrLn . myShow $ (repeat (-1) "Hello World")
  1. You are actually intending to build a list of strings, with the empty string as the default case:

In this case, you need to change the repeat function:

repeat 1 x = [x]
repeat n x 
  | n < 0 = []
  | n > 0 = x : repeat (n-1) x

Now the signature will be repeat :: (Num a, Ord a) => a -> t -> [t] and the empty case will be [].

Impredicative
  • 5,039
  • 1
  • 17
  • 43
0

Your problem is actually one where using Haskell's "infinite" lists can make for an elegant solution. The idea is to generate an infinite list of repititions of the input string, then take exactly as many as we need, then decide how we're going to print that finite sublist:

printNTimes :: Int -> String -> IO ()
printNTimes n s = putStrLn . customShow . take n . repeat $ s
  where
    customShow [] = "[]"
    customShow ss = concat ss

The standard Prelude function, repeat (not the same as the one you've defined yourself), takes a single exemplar of something and creates an infinite list of this thing by simply repeating it over and over "forever". So:

repeat "hello" = ["hello", "hello", "hello", ...]   -- not valid Haskell
repeat 3 = [3, 3, 3, ...]   -- not valid Haskell

Of course, we can never show or in any other fully concrete way realize an infinite list on a machine which after all has only finite memory. But this isn't a problem, since we'll only need the first n elements of the list, and that is what take n does in the function above. Note that when n <= 0, take n returns the empty list regardless of what it's applied to, in particuarl, take (-1) ["hello", "hello", ...] = [].

Once we have the n elements we're interested in, we can show them however we like, and that's just what customShow does: if it sees an empty list, it prints "[]", otherwise it concatenates all the strings we've just taken from our list of repeats together into one long string and shows it in the usual way.

On a sidenote, it's good practice in Haskell to separate pure functions, such as the customShow . take n . repeat part of printNTimes, from impure IO operations such as putStrLn. In printNTimes, the pure and the impure are combined by composition, but it would be better to write something like...

showNTimes :: Int -> String -> String
showNTimes n = customShow . take n . repeat
  where
    customShow [] = "[]"
    customShow ss = concat ss

And then later, perhaps in your main function, you'll have a sequence like this:

main :: IO ()
main = do
    s <- getLine
    ...
    putStrLn $ showNTimes 10 s
    ...

Good luck with your Haskelling! It's a beautiful language and rewarding to learn.

Aaron Roth
  • 456
  • 2
  • 5