I have an sml-nj project in which I want to work with a 'list of lists' structure, which has "Squares". I'm trying to insert values to the list of lists recursively, but I still haven't understood how to insert elements to a 2d list.
Note - I CAN'T USE 'REF', ONLY http://smlfamily.org/Basis/list.html#SIG:LIST.app:VAL these functions.
datatype SquareContent = Mine | Digit of int | Blank;
datatype Square = Revealed of SquareContent | Concealed of SquareContent;
fun createMineSweeperGrid (n:int)
:(Square list list)=
let
fun createMines (rowCounter:int, colCounter:int
, retGame:Square list list):(Square list list) =
if rowCounter=n then
retGame (* finished all rows, should be n lists of size n*)
else
if colCounter=n then (*finished current row, move on*)
createMines (rowCounter+1, 0, mines,retGame)
else
let
val squareToInsert = Concealed(Mine) (* I wish to insert 'squareToInsert'
to retGame[rowCounter][colCounter], it's done dynamically, but I don't know
how to do that *)
in
createMines (rowCounter, colCounter+1, retGame)
end
in
createMines (0,0,[])
end
I could insert any kind of Square, it's decided dynamically and here I gave example only of concealed Mine so you can help me.. HELP..?
The essential thing to recognize is that in Standard ML, you don't mutate existing structures; rather, you create new ones. (Standard ML does support mutable structures, via ref and its friends, but it's not something to do lightly, and I see that you've already — rightly — ruled it out.)
In general, therefore, inserting something into the middle of a linked list is pretty expensive: it requires "unwinding" the list to the point where you want to insert, then inserting the value, and lastly building a copy of everything you'd unwound. For example, here's a function that would insert a value x at index i of a list:
fun insert (x, 0, L) = x :: L
| insert (x, i, h :: t) = h :: insert (x, i - 1, t)
| insert (_, _, nil) = raise Subscript
Fortunately, your function is written so as to not have to insert anything into the middle of an already-built linked list; rather, if I understand correctly what it's trying to do, it always puts the new square at the beginning of the first list. So:
let
val squareToInsert = Concealed(Mine)
val topRow :: rest = retGame
in
createMines (rowCounter, colCounter+1, (squareToInsert::topRow)::rest)
end
Note that you'll also need to fix another bug, which is that you never actually create new rows: you have a comment about "finished current row, move on", but then it just proceeds exactly the same as if it were still in the same row (just resetting the numbers as if it had moved to a new row). To fix this, use [] :: retGame when you want to add a new row at the top, and use [[]] instead of [] for the initial board (so that it starts out with an empty row).
Related
I'm beginner in haskell and I tried to add a number in a 2D list with specific index in haskell but I don't know how to do
example i have this:
[[],[],[]]
and I would like to put a number (3) in the index 1 like this
[[],[3],[]]
I tried this
[array !! 1] ++ [[3]]
but it doesn't work
As you may have noticed in your foray so far, Haskell isn't like many other languages in that it is generally immutable, so trying to change a value, especially in a deeply nested structure like that, isn't the easiest thing. [array !! 1] would give you a nested list [[]] but this is not mutable, so any manipulations you do this structure won't be reflected in the original array, it'll be a separate copy.
(There are specialized environments where you can do local mutability, as with e.g. Vectors in the ST monad, but these are an exception.)
For what you're trying to do, you'll have to deconstruct the list to get it to a point where you can easily make the modification, then reconstruct the final structure from the (modified) parts.
The splitAt function looks like it will help you with this: it takes a list and separates it into two parts at the index you give it.
let array = [[],[],[]]
splitAt 1 array
will give you
([[]], [[],[]])
This helps you by getting you closer to the list you want, the middle nested list.
Let's do a destructuring bind to be able to reconstruct your final list later:
let array = [[],[],[]]
(beginning, end) = splitAt 1 array
Next, you'll need to get at the sub-list you want, which is the first item in the end list:
desired = head end
Now you can make your modification -- note, this will produce a new list, it won't modify the one that's there:
desired' = 3:desired
Now we need to put this back into the end list. Unfortunately, the end list is still the original value of [[],[]], so we'll have to replace the head of this with our desired' to make it right:
end' = desired' : (tail end)
This drops the empty sub-list at the beginning and affixes the modified list in its place.
Now all that's left is to recombine the modified end' with the original beginning:
in beginning ++ end'
making the whole snippet:
let array = [[],[],[]]
(beginning, end) = splitAt 1 array
desired = head end
desired' = 3:desired
end' = desired' : (tail end)
in beginning ++ end'
or, if you're entering all these as commands in the REPL:
let array = [[],[],[]]
let (beginning, end) = splitAt 1 array
let desired = head end
let desired' = 3:desired
let end' = desired' : (tail end)
beginning ++ end'
As paul mentions, things in Haskell are immutable. What you want to do must be done not be modifying the list in place, but by destructuring the list, transforming one of its parts, and restructuring the list with this changed part. One way of destructuring (via splitAt) is put forth there; I'd like to offer another.
Lists in Haskell are defined as follows:
data [] a = [] | a : [a]
This reads "A list of a is either empty or an a followed by a list of a". (:) is pronounced "cons" for "constructor", and with it, you can create nonempty lists.
1 : [] -> [1]
1 : [2,3] -> [1,2,3]
1 : 2 : 3 : [] -> [1,2,3]
This goes both ways, thanks to pattern matching. If you have a list [1,2,3], matching it to x : xs will bind its head 1 to the name x and its tail [2,3] to xs. As you can see, we've destructured the list into the two pieces that were initially used to create it. We can then operate on those pieces before putting the list back together:
λ> let x : xs = [1,2,3]
λ> let y = x - 5
λ> y : xs
[-4,2,3]
So in your case, we can match the initial list to x : y : z : [], compute w = y ++ [3], and construct our new list:
λ> let x : y : z : [] = [[],[],[]]
λ> let w = y ++ [3]
λ> [x,w,z]
[[],[3],[]]
But that's not very extensible, and it doesn't solve the problem you pose ("with specific index"). What if later on we want to change the thousandth item of a list? I'm not too keen on matching that many pieces. Fortunately, we know a little something about lists—index n in list xs is index n+1 in list x:xs. So we can recurse, moving one step along the list and decrementing our index each step of the way:
foo :: Int -> [[Int]] -> [[Int]]
foo 0 (x:xs) = TODO -- Index 0 is x. We have arrived; here, we concatenate with [3] before restructuring the list.
foo n (x:xs) = x : foo (n-1) xs
foo n [] = TODO -- Up to you how you would like to handle invalid indices. Consider the function error.
Implement the first of those three yourself, assuming you're operating on index zero. Make sure you understand the recursive call in the second. Then read on.
Now, this works. It's not all that useful, though—it performs a predetermined computation on a specified item in a list of one particular type. It's time to generalize. What we want is a function of the following type signature:
bar :: (a -> a) -> Int -> [a] -> [a]
where bar f n xs applies the transformation f to the value at index n in the list xs. With this, we can implement the function from before:
foo n xs = bar (++[3]) n xs
foo = bar (++[3]) -- Alternatively, with partial application
And believe it or not, changing the foo you already wrote into the much more useful bar is a very simple task. Give it a try!
How do you move items up in a list.
The input list would look like: let list = [1;2;3;4;5]
And the output list would look like one of the following:
[1;2;3;5;4]
.........>
[2;1;3;4;5]
...>......
Plot twist: I want to be able to move any index in the list up
From what I understand is this not something you aim to do with F# or functional languages, but it's a must have on my program.
I believe this can be done using both recursions and higher order(HO) functions, but since my knowlegde with HO's are very limited I tried to solve this using a recursion.
My approach to moving down an item in the list included a simple recursion with index and list as arguments like so:
let rec moveDownAt index list =
match index, list with
| -1, _ -> list
| 0, h1::h2::t -> h2::h1::t
| index, h::t -> h::moveDownAt (index - 1) t
| _, [] -> list
However, to move in the other direction I would need to reference the previous "head" and I assume I would have issues on the third match line | index, h::t -> h::moveDownAt (index - 1) t where i perform h:: since I add the head to the list (which would be the previous the next call if I add that argument).
Switching place on two elements means that one is moving up, and one is moving down.
Simple using the following code will solve the problem:
let moveUpAt index list = moveDownAt (index-1) list
This will displace the index making "index to be moved down" turn into "index to be moved up".
The basic idea is the following: First, return the nth element of the list. Then append the rest elements, except the nth element since you have already returned it. Here's the code:
let MoveToTop index xs =
List.nth xs index // take nth item
:: // and prepend it to the beginning of the
// original list, except the nth element
(
xs // original data
|> List.mapi
(fun i x -> i, x) // associate each element with its ordinal index
|> List.filter
(fun (i, _) -> i <> index) // allow only the elements whose index
// is not equal to requested index
|> List.map snd // remove the index from the data
// as we no longer need it
)
// test
[1; 2; 3; 4; 5]
|> MoveToTop 1 // don't forget, the index is zero-based
|> printfn "%A"
// output: [2; 1; 3; 4; 5]
Note that if index is outside the length of the list, an ArgumentException will be thrown.
A recursive algorithm is also possible, but it would be certainly less performant due to creation of excessive data and performing excessive computations.
I want to make a program insertAt where z is the place in the list, and y is the number being inserted into the list xs. Im new to haskell and this is what I have so far.
insertAt :: Int-> Int-> [Int]-> [Int]
insertAt z y xs
| z==1 = y:xs
but I'm not sure where to go from there.
I have an elementAt function, where
elementAt v xs
| v==1 = head xs
| otherwise = elementAt (v-1) (tail xs)
but I'm not sure how I can fit it in or if I even need to. If possible, I'd like to avoid append.
If this isn't homework: let (ys,zs) = splitAt n xs in ys ++ [new_element] ++ zs
For the rest of this post I'm going to assume you're doing this problem as homework or to teach yourself how to do this kind of thing.
The key to this kind of problem is to break it down into its natural cases. You're processing two pieces of data: the list you're inserting into, and the position in that list. In this case, each piece of data has two natural cases: the list you're procssing can be empty or not, and the number you're processing can be zero or not. So the first step is to write out all four cases:
insertAt 0 val [] = ...
insertAt 0 val (x:xs) = ...
insertAt n val [] = ...
insertAt n val (x:xs) = ...
Now, for each of these four cases, you need to think about what the answer should be given that you're in that case.
For the first two cases, the answer is easy: if you want to insert into the front of a list, just stick the value you're interested in at the beginning, whether the list is empty or not.
The third case demonstrates that there's actually an ambiguity in the question: what happens if you're asked to insert into, say, the third position of a list that's empty? Sounds like an error to me, but you'll have to answer what you want to do in that case for yourself.
The fourth case is most interesting: Suppose you want to insert a value into not-the-first position of a list that's not empty. In this case, remember that you can use recursion to solve smaller instances of your problem. In this case, you can use recursion to solve, for instance, insertAt (n-1) val xs -- that is, the result of inserting your same value into the tail of your input list at the n-1th position. For example, if you were trying to insert 5 into position 3 (the fourth position) of the list [100,200,300], you can use recursion to insert 5 into position 2 (the third position) of the list [200,300], which means the recursive call would produce [200,300,5].
We can just assume that the recursive call will work; our only job now is to convert the answer to that smaller problem into the answer to the original problem we were given. The answer we want in the example is [100,200,300,5] (the result of inserting 5 into position 4 of the list [100,200,300], and what we have is the list [200,300,5]. So how can we get the result we want? Just add back on the first element! (Think about why this is true.)
With that case finished, we've covered all the possible cases for combinations of lists and positions to update. Since our function will work correctly for all possibilities, and our possibilities cover all possible inputs, that means our function will always work correctly. So we're done!
I'll leave it to you to translate these ideas into Haskell since the point of the exercise is for you to learn it, but hopefully that lets you know how to solve the problem.
You could split the list at index z and then concatenate the first part of the list with the element (using ++ [y]) and then with the second part of the list. However, this would create a new list as data is immutable by default. The first element of the list by convention has the index 0 (so adjust z accordingly if you want the meaning of fist elemnt is indexed by 1).
insertAt :: Int -> Int-> [Int] -> [Int]
insertAt z y xs = as ++ (y:bs)
where (as,bs) = splitAt z xs
While above answers are correct, I think this is more concise:
insertAt :: Int -> Int-> [Int]-> [Int]
insertAt z y xs = (take z xs) ++ y:(drop z xs)
I'm new to SML and I'm attempting to get the index of an item in a list. I know that using List.nth will give me the value of an item at a index position, but I want the index value. There may even be a built in function that I'm not aware of. In my case, the list will not contain duplicates so if the item is in the list I get the index, if not it returns ~1. Here is the code I have so far. It works, but I don't think it is very clean:
val L=[1,2,3,4,5];
val m=length L-1;
fun Index(item, m, L)=if m<0 then ~1 else
if List.nth(L, m)=item then m else Index(item,m-1,L);
To elaborate on my previous comment, I suggest some changes for an implementation that fits better in the ML idiom:
fun index(item, xs) =
let
fun index'(m, nil) = NONE
| index'(m, x::xr) = if x = item then SOME m else index'(m + 1, xr)
in
index'(0, xs)
end
The individual changes are:
Have index return a value of type int option. NONE means the item is not in the list, SOME i means it is in the list, and the index of its first occurrence is i. This way, no special values (~1) need be used and the function's intended usage can be inferred from its type.
Hide the parameter m by renaming the function to index' and wrapping it into an outer function index that calls it with the appropriate arguments. The prime character (`) often indicates auxiliary values.
Use pattern matching on the list to get to the individual elements, eliminating the need for List.nth.
Also note that most commonly, function and variable names begin with a lowercase letter (index rather than Index), while capital letters are used for constructor constants (SOME) and the like.
I would like to propose a simpler and less efficient version of this index function. I agree that it is not as desirable to use exceptions rather than int option, and that it is not tail-recursive. But it is certainly easier to read and thus may serve as learning material:
fun index (x, []) = raise Subscript
| index (x, y::ys) =
if x = y then 0 else 1 + index (x, ys)
fun index(list,n)=
= if n=0 then hd(list) else index(tl(list),n-1);
val index = fn : 'a list * int -> 'a
index([1,2,3,4,5],2);
val it = 3 : int
index([1,2,3,4,5],0);
val it = 1 : int
Im trying to swap the first and last element of a list in haskell. I've tried pattern matchnig, expressions, functions, etc. This is my last attempt:
cambio xs = [ cabeza++([x]++cola)|x<-xs, cabeza <- init x, cola <- last x, drop 1 x, drop 0 ([init x])]
My compiler throws the next error:
Couldn't match expected type `Bool' with actual type `[a0]'
In the return type of a call of `drop'
In the expression: drop 1 x
In a stmt of a list comprehension: drop 1 x
Can anyone help me? I've tried to do this for 2 days
Here are a few hints:
You can't solve this with list comprehension.
Identify the base (trivial) cases - empty list and list of one element. Write equations that cover those cases.
In all other cases the length of the input list will be >= 2. The list you want is
[z] ++ xs ++ [a]
where z is the last element, a the first element of the input list and xs the middle part of the input.
Now tell me (or yourself), how long will xs be, if the length of the input string was k?
Write the equation that covers the case of lists with more than 1 elements. You can use functions like head, last, length, drop or take.
I think that lists aren't the best data structure for doing this, but here it goes:
swap list = last list : (init . tail $ list) ++ [head list]
This is going to require traversing the list and will be slow on long lists. This is the nature of linked lists.
Updated with base cases from question asker:
swap [] = []
swap [a] = [a]
swap list = last list : (init . tail $ list) ++ [head list]
This is a fairly straightforward thing to do, especially with the standard list functions:
swapfl [] = []
swapfl [x] = [x]
swapfl (x:xs) = (last xs : init xs) ++ [x]
Or without them (although this is less readable and usually not done, and not recommended):
swapfl' [] = []
swapfl' [x] = [x]
swapfl' (x:xs) = let (f, g) = sw x xs in f:g
where sw k [y] = (y, [k])
sw k (y:ys) = let (n, m) = sw k ys in (n, y:m)
Or one of many other ways.
I hope that helps ... I know I didn't do much explaining, but frankly, it's hard to tell exactly what you were having trouble with as far as this function is concerned, seeing as you also seem to completely misunderstand list comprehensions. I think it might be most beneficial if I explain those instead?
And why this cant be solved with a list comprehension? I tough they were like functions but with a different form
Not really. List comprehensions are useful for easily defining lists, and they're very closely related to set-builder notation in mathematics. That would not be useful for this particular application, because, while they're very good at modifying the elements of a list, comprehensions are not very good at reordering lists.
In a comprehension, you have three parts: the definition of an element in the list, one or more input lists, and zero or more predicates:
[ definition | x <- input1, y <- input2, predicate1, predicate2 ]
The definition describes a single element of the list we're making, in terms of the variables the arrows in the inputs are pointing at (x and y in this case). Each input has a list on the right of the arrow, and a variable on the left. Each element in the list we're making is built by extracting each combination of elements from the input lists into those variables, and evaluating the definition part using those values. For example:
[ x + y | x <- [1, 3], y <- [2, 4] ]
This generates:
[1 + 2, 1 + 4, 3 + 2, 3 + 4] == [3, 5, 5, 7]
Also, you can include predicates, which are like filters. Each predicate is a boolean expression defined in terms of the input elements, and each is evaluated whenever a new list element is. If any of the predicates come out to be false, those elements aren't put in the list we're making.
Let's look at your code:
cambio xs = [ cabeza++([x]++cola) | x<-xs, cabeza <- init x, cola <- last x,
drop 1 x, drop 0 ([init x])]
The inputs for this comprehension are x <- xs, cabeza <- init x, and cola <- last x. The first one means that every element in xs is going to be used to define elements for the new list, and each element is going to be named x. The other two don't make any sense, because init and last are type [a] -> a, but are on the right side of the arrow and so must be lists, and x must be an element of a list because it's on the left side of its arrow, so in order for this to even compile, xs would have to be type [[[a]]], which I'm sure is not what you want.
The predicates you used are drop 1 x and drop 0 [init x]. I kind of understand what you were trying to do with the first one, dropping the first element of the list, but that wouldn't work because x is just an element of the list, not the list itself. In the second one, drop 0 means "remove zero elements from the beginning of the following list", which would do absolutely nothing. In either case, putting something like that in a predicate wouldn't work because the predicate needs to be a boolean value, which is why you got the compiler error. Here's an example:
pos xs = [ x | x <- xs, x >= 0 ]
This function takes a list of numbers, removes all the negative numbers, and returns the result. The predicate is the x >= 0, which is a boolean expression. If the expression evaluates to false, the element being evaluated is filtered out of the resulting list.
The element definition you used is cabeza ++ [x] ++ cola. This means "Each element in the resulting list is itself a list, made up of all elements in the list cabeza, followed by a single element that contains x, followed by all elements in the list cola", which seems like the opposite of what you were going for. Remember that the part before the pipe character defines a single element, not the list itself. Also, note that putting square brackets around a variable creates a new list that contains that variable, and only that variable. If you say y = [x], this means that y contains a single element x, and doesn't say anything about whether x is a list or not.
I hope that helps clear some things up.