How can I use Haskell exception for index negative - haskell

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?

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

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.

Related

How can i use conditionals in list comprehension?

I am trying to build a list of 0's using list comprehension. But i also want to make an index 1 where i choose in the list. For example myList 5 2 = [0,1,0,0,0] where 5 is the number of elements and 2 is the index.
myList el index = [0 | n <- [1..el], if n == index then 1 else 0]
but this results in an error.
The smallest change that fixes that is
myList el index = [if n == index then 1 else 0 | n <- [1..el]]
Note that what's at the left of | is what generates the list elements. A list comprehension of the form [ 0 | ...] will only generate zeros, and the ... part only decides how long is the resulting list.
Further, in your code the compiler complains because at the right of | we allow only generators (e.g. n <- someList), conditions (e.g. x > 23), or new definitions (let y = ...). In your code the if ... is interpreted to be a condition, and for that it should evaluate to a boolean, but then 1 makes the result a number, triggering a type error.
Another solution could be
myList el index = replicate (index-1) 0 ++ [1] ++ replicate (el-index) 0
where replicate m 0 generates a list with m zeros, and ++ concatenates.
Finally, note that your index is 1-based. In many programming languages, that's unconventional, since 0-based indexing is more frequently used.

Search of element from List in the String

I have a list like List = ["google","facebook","instagram"] and a string P1 = "https://www.google.co.in/webhp?pws=0&gl=us&gws_rd=cr".
Now I need to find which element of List is present inside the P1.
For this I implemented below recursive function, but it returns ok as final value, is there a way that when (in this case) google is found, then H is returned and terminate the other recursive calls in stack.
I want this function to return google.
traverse_list([],P1)-> ok;
traverse_list([H|T],P1) ->
Pos=string:str(P1,H),
if Pos > 1 ->
io:fwrite("Bool inside no match is ~p~n",[Pos]),
io:fwrite("inside bool nomathc, ~p~n",[H]),
H;
true->
io:fwrite("value found :: ~p~n",[Pos])
end,
traverse_list(T,P1).
It returns ok because the stop condition of your recursion loop does it:
traverse_list([],P1)-> ok;
For this you should use lists:filter/2 or a list comprehension:
List = ["google","facebook","instagram"],
P1 = "https://www.google.co.in/webhp?pws=0&gl=us&gws_rd=cr",
lists:filter(fun(X) -> string:str(P1,X) > 1 end,List),
% or
[X || X <- List, string:str(P1,X) > 1],

List Comprehension with Argument Not Terminating

Let's say I want to find a list of (Integer, Integer) where i and j are >= 2, and i + j + 2*i*j < 100:
ghci> take 10 [ (i, j) | i <- [2..], j <- [2..], i * j + 2*i*j < 100]
[(2,2),(2,3),(2,4),(2,5),(2,6),(2,7),(2,8),(2,9),(2,10),(2,11)]
However, when I change this function to accept an argument n (rather than 100), it's not terminating for me after ~15 seconds.
ghci> let f n = take 10 [ (i, j) | i <- [2..], j <- [2..], i * j + 2*i*j < n]
ghci> f 5
Interrupted.
If you call f 100 instead of f 5, you'll get the same results as the first example. The problem isn't the fact that it's a function; it's the fact that you're trying to extract the first 10 elements of a filtered infinite list when the filter will never return that many elements.
There are no values of i and j greater than or equal to 2 for which 3*i*j < 5, so the returned list for n=5 should be empty. But Haskell can't determine that it's empty until it's examined all possible values of i and j. As written, that's an infinite number of possibilities. Since it never runs out of possible inputs, and never gets to the desired ten outputs, it never terminates.
The other thing to notice is that the first ten answers to the problem for n=100 all have i=2. If you try a number in between, such 50, you can watch the function generate the first part of the correct answer for that case - specifically, in the case of n=50, the seven elements which have i equal to 2. But after that, despite there being more than the needed three additional solutions to get to ten elements, it hangs. That's becausee those additional solutions all have i > 2. Haskell doesn't find them because it never gets past looking at the "first infinity" cases where i is 2 and j is any number at all.

Haskell: Getting a single bit from a String of bits

So I'm using a Grey-code generator to generate all possible bit Strings of length 6. The generator is as follows:
gray :: Integer -> String
gray n
| n == 0 = [""]
| n > 0 = map (++"0") (gray (n-1)) ++
map (++"1") (reverse (gray (n-1)))
recipes = gray 6
Then, I'm attempting to get a specific bit from each of these Strings and convert that bit to an Integer. I'm doing this in the following way:
cost' :: String -> Cost
cost' r i = toInteger( ord ( r!!i ) )
Now, for some reason this isn't working. Regardless of what 'i' value I use, the function cost' will either result in 48 (if the bit in position 2 of the list is 0 --> ex. '100000') or 49 (if the bit in position 2 of the list is 1 --> ex. '101000').
It doesn't make any sense to me why this is.. It's my understanding that Strings are stored as lists in Haskell, and that to get a certain element 'i' from a list 'r' in Haskell, you execute 'r!!i'.
That's because ord returns the code point number of the character, and '0' is code point 48, '1' is code point 49. The function you want to use is digitToInt.

Given length and index - how to create an "unit" array?

How can I create an array of length n, all zeroes, except for some index i being equal to 1.0?
For example, if my magic function is foo it would work as follows:
foo:: Int -> Int -> [Double]
> foo 3 0
[1.0, 0.0, 0.0]
> foo 2 1
[0.0, 1.0]
> foo 1 1
** Exception: index greater than length!
Having a brain freeze...any help appreciated.
unitList :: Int -> Int -> [Double]
unitList len index
| index < len = replicate index 0 ++ 1 : replicate (len - 1 - index) 0
| otherwise = error "index out of range"
Note that that's a list, not an array. Lists have O(i) indexing, arrays O(1), so one shouldn't confuse the names of the datatypes.
To create a list (as your type signature and examples suggest), you can use range syntax to create a list of indices and then call map to go over the indices, compare each index to the index the user supplied and map it to 1.0 or 0.0 accordingly.
foo n k | n < 0 || n >= k = error "not in range"
| otherwise = map (fromIntegral.fromEnum.(==k))[0..(n-1)]

Resources