Related
I have just started learning Haskell and I am trying to write some basic functions in order to get a better understanding of this language.
I want to write a function which takes a list and an Int (N) as argument and returns the element at index N in the list, without using the !! operator or any built-in function.
Here is what I tried :
myHead :: [a] -> a
myHead (x:_) = x
myHead [] = error "head: empty list"
myNth :: [a] -> Int -> a
myNth x i = if i < 0
then error "nth: index can't be negative"
else myNthIterator x i 0
myNthIterator :: [a] -> Int -> Int -> a
myNthIterator [] i n = error "nth: bad index"
myNthIterator (_:x) i n = if i == n
then myHead x
else myNthIterator x i ( n + 1 )
It works but it's shifted to the right. For example myNth [1, 2, 3, 4] 2 would give 4 and not 3.
From what I understand, (_:x) removes the first element of the list and I don't see how to iterate through the list element by element.
Could someone put me on the trail? I find it difficult to find resources for beginners in this language.
We can use Maybe to model whether the index was valid.
nth :: Int -> [a] -> Maybe a
nth 0 (x : _) = Just x
nth n (x : xs) = nth (n - 1) xs
nth _ [] = Nothing
We can pattern match on the index to get our base case, and the list to get the first element and tail.
What you're doing there with (_:x) is called "pattern matching" in case you didn't know. The general pattern for iterating through a list would be (x : xs) where x is head element of the list being matched and xs is the rest of the list. If you use _ you don't remove anything it is still matched to _ which is the convention for saying "I won't use this".
With that you can make a function like this:
myNth :: [a] -> Int -> a
myNth [] _ = error "out of range"
myNth (x : xs) 0 = x
myNth (_ : xs) n = myNth xs (n - 1)
Whenever myNth is called it will go top to bottom over those definitions trying to match the patterns to the input. So when you call myNth [10,11] 1 it won't match the first clause because [10,11] doesn't match an empty list, it won't match the second either because 1 is not 0 and so it will match the third case where it will match the [10,11] on (10 : [11]), therefore _ is 10 and xs is [11] and 1 will be matched as n. Then it calls itself recursively, as myNth [11] 0. Now that will match the second case and it will return x from the match of [11] on (11 : [])
Like 414owen said you can use the Maybe a type to avoid using error.
P.S.: I don't know how beginner you are but I assume you know of the : operator, it prepends an element to a list... If you go more in depth (afaik) every list is actually stored as a sequence of a:(b:(c:(d:(e:[])))) which is equivalent to [a,b,c,d,e] which is equivalent to a:[b,c,d,e] etc.
It works but it's shifted to the right. For example myNth [1, 2, 3, 4] 2 would give 4 and not 3.
myNthIterator (_:x) i n = if i == n
then myHead x
else myNthIterator x i ( n + 1 )
Let us look at myNthIterator [1..4] 1 1
myNthIterator [1..4] 1 1 -- replace [a, b] with (a: (b : []))
== myNthIterator (1 : [2, 3, 4]) 1 1
-- matching with `myNthIterator (_:x) i n` will result in
-- 1 ~ _
-- x ~ [2, 3, 4]
-- i ~ 1
-- n ~ 1
== if 1 == 1 then myHead [2, 3, 4] else myNthIterator [2, 3, 4] 1 (1 + 1)
== myHead [2, 3, 4]
== 2
So (_:x) matching against (1 : [2, 3, 4]) is suspicious. A first step in fixing it is to replace (_:x) by (x:xs).
myNthIterator (x:xs) i n = ...
In our example this would mean x == 1 and xs == [2, 3, 4].
How do you find nth elements in the matrix at a given row and column position? For example, if you have
type Matrice a = [[a]]
example :: Matrice Int
example = [ [3, 5],
[2, 1],
[0, 4],
[6, 8] ]
Prelude > example 0 1
5
Prelude > example 2 0
0
Prelude > example 1 1
2
I know how to work out with only given list such as
nth :: Int -> [a] -> Maybe a
nth _ [] = Nothing
nth 1 (x : _) = Just x
nth n (_ : xs) = nth (n - 1) xs
But my question is, how do you access nth element in a matrix as in the given example
Just handle each list individually, and !! will work:
Prelude> example
[[3,5],[2,1],[0,4],[6,8]]
Prelude> :t example
example :: Matrice Int
Prelude> example !! 0 !! 1
5
But lists are probably not the right data structure for this, because indexing is O(n). Depending on your task, Data.Vector or Data.Array may be better suited. See also Haskell: Lists, Arrays, Vectors, Sequences.
!! can be used for accessing an element by index, but be careful, since it's raising an exception, if the index is too large.
example !! 2 !! 0
And you've already written a function for accessing nth element of a list, just apply it twice:
nth :: Int -> Int -> [[a]] -> Maybe a
nth k n matrix = nth' n =<< nth' k matrix
where
nth' _ [] = Nothing
nth' 0 (x: _) = Just x
nth' n (_ : xs) = nth' (n - 1) xs
Or using your created Matrice type:
nth :: Matrice a -> Int -> Int -> Maybe a
nth matrix k n = nth' n =<< nth' k matrix
where
nth' _ [] = Nothing
nth' 0 (x: _) = Just x
nth' n (_ : xs) = nth' (n - 1) xs
I have list of lists of Int and I need to add an Int value to the last list from the list of lists. How can I do this? My attempt is below
f :: [[Int]] -> [Int] -> Int -> Int -> Int -> [[Int]]
f xs [] cur done total = [[]]
f xs xs2 cur done total = do
if total >= length xs2 then
xs
else
if done == fib cur then
f (xs ++ [[]]) xs2 (cur + 1) 0 total
else
f ((last xs) ++ [[xs2!!total]]) xs2 cur (done + 1) (total + 1)
The problem is:
We have a list A of Int
And we need to slpit it on N lists B_1 ,..., B_n , length of B_i is i-th Fibonacci number.
If we have list [1 , 2 , 3 , 4 , 5 , 6 , 7] (xs2 in my code)
The result should be [[1] , [2] , [3 , 4] , [5 , 6 , 7]]
The easy way to deal with problems like this is to separate the problem into sub-problems. In this case, you want to change the last item in a list. The way you want to change it is by adding an item to it.
First let's tackle changing the last item of a list. We'll do this by applying a function to the last item, but not to any other items.
onLast :: [a] -> (a -> a) -> [a]
onLast xs f = go xs
where
go [] = []
go [x] = [f x]
go (x:xs) = x:go xs
You want to change the last item in the list by adding an additional value, which you can do with (++ [value]).
Combining the two with the value you want to add (xs2!!total) we get
(onLast xs (++ [xs2!!total]))
f :: [[Int]] -> Int -> [[Int]]
f [] _ = []
f xs i = (take n xs) ++ [[x + i | x <- last xs]]
where n = (length xs) - 1
last = head . (drop n)
For example,
*Main> f [[1, 2, 3], [], [4, 5, 6]] 5
[[1,2,3],[],[9,10,11]]
*Main> f [[1, 2, 3]] 5
[[6,7,8]]
*Main> f [] 3
You approach uses a do block, this is kind of weird since do blocks are usually used for monads. Furthermore it is rather unclear what cur, done and total are doing. Furthermore you use (!!) :: [a] -> Int -> a and length :: [a] -> Int. The problem with these functions is that these run in O(n), so it makes the code inefficient as well.
Based on changed specifications, you want to split the list in buckets with length the Fibonacci numbers. In that case the signature should be:
f :: [a] -> [[a]]
because as input you give a list of numbers, and as output, you return a list of numbers. We can then implement that as:
f :: [a] -> [[a]]
f = g 0 1
where g _ _ [] = []
g a b xs = xa : g b (a+b) xb
where (xa,xb) = splitAt b xs
This generates:
*Main> f [1,2,3,4,5,6]
[[1],[2],[3,4],[5,6]]
*Main> f [1,2,3,4,5,6,7]
[[1],[2],[3,4],[5,6,7]]
*Main> f [1,2,3,4,5,6,7,8]
[[1],[2],[3,4],[5,6,7],[8]]
*Main> f [1,2,3,4,5,6,7,8,9]
[[1],[2],[3,4],[5,6,7],[8,9]]
The code works as follows: we state that f = g 0 1 so we pass the arguments of f to g, but g also gets an 0 and a 1 (the first Fibonacci numbers).
Each iteration g checks whether we reached the end of the list. If so, we return an empty list as well. Otherwise we determine the last Fibonacci number that far (b), and use a splitAt to obtain the first b elements of the list we process, as well as the remainder. We then emit the first part as head of the list, and for the tail we calculate the next Fibonacci number and pass that to g with the tail of splitAt.
I have a function that returns a list like this:
[ [1, 2, 3], [], [5], [5,6], []]
But I want to replace the empty lists with 0, so that it looks like this
[ [1, 2, 3], [0], [5], [5,6], [0]]
So far I have tried filter and map with little success. Can someone please point me in the right direction?
Here is the code in question:
knightPlace:: [Int] -> [[Int]]
knightPlace n = makeboard n
where
makeboard n = [x | i<-[0..(length n -1 )], x <- [checkPos i]]
-- checkPos add zero
checkPos i = [j+1 | j<-[0..(length n -1 )], queenFilter n i j]
-- filters all rows, cols and diags, also knights
queenFilter n i j = and [n!!(i) == 0 && n!!(k) /=(j+1) && (n!!(k)==0 || (abs(n!!(k)-(j+1))/=abs(i-k))) && (n!!(k)==0 ||not( ((abs(i-k)==2)&& (abs(n!!(k)-(j+1))==1)) ||((abs(i-k)==1)&& (abs(n!!(k)-(j+1))==2)))) | k<-[0..(length n - 1)] ]
Called like
knightPlace [0, 0, 6, 0, 0, 4, 0, 0]
Consider that if you have a function foo that can transform [] to [0] and return every other list untouched, map foo is the final function that you want.
Replace xs with ys in l,
replaceWith :: [a] -> [a] -> [[a]]
replaceWith xs ys l = map (\x -> if x == xs then ys else x) l
In the case here,
replaceWith [] [0] [[1, 2, 3],[],[5],[5,6],[]]
Change your function with
knightPlace n = map (\x -> if null x then [0] else x) $ makeboard n
Also consider using pointfree style
knightPlace = map (\x -> if null x then [0] else x) . makeboard
Does Haskell have similar syntactic sugar to Python List Slices?
For instance in Python:
x = ['a','b','c','d']
x[1:3]
gives the characters from index 1 to index 2 included (or to index 3 excluded):
['b','c']
I know Haskell has the (!!) function for specific indices, but is there an equivalent "slicing" or list range function?
There's no built-in function to slice a list, but you can easily write one yourself using drop and take:
slice :: Int -> Int -> [a] -> [a]
slice from to xs = take (to - from + 1) (drop from xs)
It should be pointed out that since Haskell lists are singly linked lists (while python lists are arrays), creating sublists like that will be O(to), not O(to - from) like in python (assuming of course that the whole list actually gets evaluated - otherwise Haskell's laziness takes effect).
If you are trying to match Python "lists" (which isn't a list, as others note) then you might want to use the Haskell vector package which does have a built in slice. Also, Vector can be evaluated in parallel, which I think is really cool.
No syntactic sugar. In cases where it's needed, you can just take and drop.
take 2 $ drop 1 $ "abcd" -- gives "bc"
I don't think one is included, but you could write one fairly simply:
slice start end = take (end - start + 1) . drop start
Of course, with the precondition that start and end are in-bounds, and end >= start.
Python slices also support step:
>>> range(10)[::2]
[0, 2, 4, 6, 8]
>>> range(10)[2:8:2]
[2, 4, 6]
So inspired by Dan Burton's dropping every Nth element I implemented a slice with step. It works on infinite lists!
takeStep :: Int -> [a] -> [a]
takeStep _ [] = []
takeStep n (x:xs) = x : takeStep n (drop (n-1) xs)
slice :: Int -> Int -> Int -> [a] -> [a]
slice start stop step = takeStep step . take (stop - start) . drop start
However, Python also supports negative start and stop (it counts from end of list) and negative step (it reverses the list, stop becomes start and vice versa, and steps thru the list).
from pprint import pprint # enter all of this into Python interpreter
pprint([range(10)[ 2: 6], # [2, 3, 4, 5]
range(10)[ 6: 2:-1], # [6, 5, 4, 3]
range(10)[ 6: 2:-2], # [6, 4]
range(10)[-8: 6], # [2, 3, 4, 5]
range(10)[ 2:-4], # [2, 3, 4, 5]
range(10)[-8:-4], # [2, 3, 4, 5]
range(10)[ 6:-8:-1], # [6, 5, 4, 3]
range(10)[-4: 2:-1], # [6, 5, 4, 3]
range(10)[-4:-8:-1]]) # [6, 5, 4, 3]]
How do I implement that in Haskell? I need to reverse the list if the step is negative, start counting start and stop from the end of the list if these are negative, and keep in mind that the resulting list should contain elements with indexes start <= k < stop (with positive step) or start >= k > stop (with negative step).
takeStep :: Int -> [a] -> [a]
takeStep _ [] = []
takeStep n (x:xs)
| n >= 0 = x : takeStep n (drop (n-1) xs)
| otherwise = takeStep (-n) (reverse xs)
slice :: Int -> Int -> Int -> [a] -> [a]
slice a e d xs = z . y . x $ xs -- a:start, e:stop, d:step
where a' = if a >= 0 then a else (length xs + a)
e' = if e >= 0 then e else (length xs + e)
x = if d >= 0 then drop a' else drop e'
y = if d >= 0 then take (e'-a') else take (a'-e'+1)
z = takeStep d
test :: IO () -- slice works exactly in both languages
test = forM_ t (putStrLn . show)
where xs = [0..9]
t = [slice 2 6 1 xs, -- [2, 3, 4, 5]
slice 6 2 (-1) xs, -- [6, 5, 4, 3]
slice 6 2 (-2) xs, -- [6, 4]
slice (-8) 6 1 xs, -- [2, 3, 4, 5]
slice 2 (-4) 1 xs, -- [2, 3, 4, 5]
slice (-8)(-4) 1 xs, -- [2, 3, 4, 5]
slice 6 (-8)(-1) xs, -- [6, 5, 4, 3]
slice (-4) 2 (-1) xs, -- [6, 5, 4, 3]
slice (-4)(-8)(-1) xs] -- [6, 5, 4, 3]
The algorithm still works with infinite lists given positive arguments, but with negative step it returns an empty list (theoretically, it still could return a reversed sublist) and with negative start or stop it enters an infinite loop. So be careful with negative arguments.
I had a similar problem and used a list comprehension:
-- Where lst is an arbitrary list and indc is a list of indices
[lst!!x|x<-[1..]] -- all of lst
[lst!!x|x<-[1,3..]] -- odd-indexed elements of lst
[lst!!x|x<-indc]
Perhaps not as tidy as python's slices, but it does the job. Note that indc can be in any order an need not be contiguous.
As noted, Haskell's use of LINKED lists makes this function O(n) where n is the maximum index accessed as opposed to python's slicing which depends on the number of values accessed.
Disclaimer: I am still new to Haskell and I welcome any corrections.
When I want to emulate a Python range (from m to n) in Haskell, I use a combination of drop & take:
In Python:
print("Hello, World"[2:9]) # prints: "llo, Wo"
In Haskell:
print (drop 2 $ take 9 "Hello, World!") -- prints: "llo, Wo"
-- This is the same:
print (drop 2 (take 9 "Hello, World!")) -- prints: "llo, Wo"
You can, of course, wrap this in a function to make it behave more like Python. For example, if you define the !!! operator to be:
(!!!) array (m, n) = drop m $ take n array
then you will be able to slice it up like:
"Hello, World!" !!! (2, 9) -- evaluates to "llo, Wo"
and use it in another function like this:
print $ "Hello, World!" !!! (2, 9) -- prints: "llo, Wo"
I hope this helps, Jon W.
Another way to do this is with the function splitAt from Data.List -- I find it makes it a little easier to read and understand than using take and drop -- but that's just personal preference:
import Data.List
slice :: Int -> Int -> [a] -> [a]
slice start stop xs = fst $ splitAt (stop - start) (snd $ splitAt start xs)
For example:
Prelude Data.List> slice 0 2 [1, 2, 3, 4, 5, 6]
[1,2]
Prelude Data.List> slice 0 0 [1, 2, 3, 4, 5, 6]
[]
Prelude Data.List> slice 5 2 [1, 2, 3, 4, 5, 6]
[]
Prelude Data.List> slice 1 4 [1, 2, 3, 4, 5, 6]
[2,3,4]
Prelude Data.List> slice 5 7 [1, 2, 3, 4, 5, 6]
[6]
Prelude Data.List> slice 6 10 [1, 2, 3, 4, 5, 6]
[]
This should be equivalent to
let slice' start stop xs = take (stop - start) $ drop start xs
which will certainly be more efficient, but which I find a little more confusing than thinking about the indices where the list is split into front and back halves.
Why not use already existing Data.Vector.slice together with Data.Vector.fromList and Data.Vector.toList (see https://stackoverflow.com/a/8530351/9443841)
import Data.Vector ( fromList, slice, toList )
import Data.Function ( (&) )
vSlice :: Int -> Int -> [a] -> [a]
vSlice start len xs =
xs
& fromList
& slice start len
& toList
I've wrote this code that works for negative numbers as well, like Python's list slicing, except for reversing lists, which I find unrelated to list slicing:
slice :: Int -> Int -> [a] -> [a]
slice 0 x arr
| x < 0 = slice 0 ((length arr)+(x)) arr
| x == (length arr) = arr
| otherwise = slice 0 (x) (init arr)
slice x y arr
| x < 0 = slice ((length arr)+x) y arr
| y < 0 = slice x ((length arr)+y) arr
| otherwise = slice (x-1) (y-1) (tail arr)
main = do
print(slice (-3) (-1) [3, 4, 29, 4, 6]) -- [29,4]
print(slice (2) (-1) [35, 345, 23, 24, 69, 2, 34, 523]) -- [23,24,69,32,34]
print(slice 2 5 [34, 5, 5, 3, 43, 4, 23] ) -- [5,3,43]
Obviously my foldl version loses against the take-drop approach, but maybe someone sees a way to improve it?
slice from to = reverse.snd.foldl build ((from, to + 1), []) where
build res#((_, 0), _) _ = res
build ((0, to), xs) x = ((0, to - 1), x:xs)
build ((from, to), xs) _ = ((from - 1, to - 1), xs)
sublist start length = take length . snd . splitAt start
slice start end = snd .splitAt start . take end