0
votes

I am trying to solve one of my Haskell question. The question asks me to that extracts a slice of a list of integers. Function should take a list and two indexes new list number contains between two indexes.

For this function;

  • First index should smaller than second index
  • First index cannot be negative number
    • we cannot use any built-in functions

example:

makeSlice [1,2,3,4,5] 2 3
[3,4]
makeSlice [1,2,3,4,5] (-1) 3
*** Exception: First index cannot be negative

I tried a few option but below function if I give positive number I am getting "First index cannot be negative" exception

makeSlice :: [a] -> Int -> Int -> [a]
makeSlice [] _ _ =[]

makeSlice (h:t) i k

    |k < 0 = []
    | i>k  = error "First index cannot be greater than second index (i > k)"
    | i< 0 = error "First index cannot be negative (i < 0)!"
    | i>0 = makeSlice t (i - 1) (k - 1)
    | otherwise = h:makeSlice t (i -1 ) (k - 1)

Can you help me to find where I am making wrong?

2
I guess your problem might be in lack of terminating term for recursion. You subtract one from i on each call but recursion ends only in error. - GrayCat
If you make it to the otherwise case, then you know i< 0 is False and i>0 is False. Now think about what this implies about the value of (i -1 ). Is that what you intended? - Daniel Wagner
Hey @DanielWagner I guess same that @GrayCat mentioned. This is the recursion part I guess so when not i > 0 I should get exception but I could not get it. Also did you say if you use "otherwise" case when i < 0 False then i > 0 False? - macintosh
@macintosh You check both that i< 0 and i>0 before hitting the otherwise case. So if you hit the otherwise case, both of those must be False. - Daniel Wagner
I got it, so only when i > 0 should i - 0 otherwise should on i - macintosh

2 Answers

1
votes

Add terminating condition for your recursion. On each call you subtract one from i and when it reaches below 0 you just throw error.

0
votes

Probably the easiest approach to this uses the Prelude take and drop functions to process the list. Then you just need to do the bounds checking:

slice :: Int -> Int -> [a] -> Either String [a]
slice from to lst
  | from < 0 = Left "First index cannot be negative (i < 0)!"
  | to < from = Left "First index cannot be greater than second index (i > k)"
  | otherwise = Right $ take (to - from) $ drop from $ lst

Here I'm using Either to report either success or failure. On the one hand that disagrees with the problem as stated; on the other, it gives callers a chance to handle the error without immediately terminating the program, which is more polite.