I am really new to Haskell and also really confused about how to implement for loops since I know we need to use recursion for them.
For example, I have a list [1,2,2,4,1] and want to write a function to change every 2 to a 3. How would I go about doing this? In Java, I know I would write the following
public void replace_two(List<Integer> ints) {
int i = 0;
for (int x: ints) {
if (x == 2) {
ints.set(i, 3);
}
i++;
}
System.out.println(ints);
}
but I am not sure how I could reproduce something else like this with Haskell?
There's not a single replacement for a for loop in Haskell. The replacement depends on exactly what you want to do. In this case, a map would be appropriate:
replace_two = map go
where
go 2 = 3
go x = x
And it works like this:
Prelude> replace_two [1,2,2,4,1]
[1,3,3,4,1]
Prelude>
Haskell uses a combination of different ways to 'sort of' loop over data, e.g. list.
The two important things helping this is:
Ease of declaring a function and passing it around similar to what we do to a variable in oops languages
Extensive pattern matching
So for example I declare a function in haskell to return 2 if input is 3 else return input.
return2 x = if x == 3 then 2 else x
Now we want to apply this function to every element of the list. So we will use pattern matching.
apply (x:xs) = return2 x : apply xs
apply [] = []
Here the pattern x:xs will break the list and take the first element in x while xs will have the remainder of the list. Inside the function you can see we have applied it recursively.
I have not checked the above code in IDE so it might have syntax errors, also there are other things you will want to validate (end of list, in above code the function would cause exception).
The above pattern is quite common, so there is another function in the core libraries that can do this, and is called map. So you could do:
map return2 [your list]
As I said, in haskell there are many ways to essentially loop over things, but at the base they break down to applying the function to individual items in the data structure. There are many haskell functions built on top of it like map, fold, etc.
I would suggest you use one of the several resources online to get more familiar with Haskell constructs. One that I liked and was easy to follow is Learn you a Haskell
Using map with an anonymous function:
λ> map (\x -> if x==2 then 3 else x) [1,2,2,4,1]
[1,3,3,4,1]
Another basic approach using patterns and recursion.
replace :: [Int] -> [Int]
replace [] = [] -- base case
replace (2:x) = 3:replace(x) --if 2 then replace by 3
replace (y:x) = y:replace(x) -- do nothing
Except map, maybe you can use forM from Control.Monad to mimic the for loop in other imperative languages:
import Control.Monad
arr = [1, 2, 2, 4, 1]
forM arr $ \i ->
if i == 2 then return 3 else return i
However, you need to understand what is Monad.
Related
I am writing a function that will take a list of list and merge it into sorted pairs of list. For example [[1],[9],[8],[7],[4],[5],[6]] would return [[1,9],[7,8],[4,5],[6]]. This is my first attempt at SML. I keep getting this error: operator and operand don't agree [overload conflict].
fun mergePass[] = []
| mergePass(x::[]) = x::[]
| mergePass(x::y::Z) =
if x<y
then (x # y)::mergePass(Z)
else (y # x)::mergePass(Z);
Edit: If mergePass is called on [[1,9],[7,8],[4,5],[6]] I will need it to return [[1,7,8,9],[4,5,6]].
This merge function takes two sorted lists
fun merge([],y) = y
| merge(x,[]) = x
| merge(a::x,b::y) =
if a < b then a::merge(x,b::y)
else b::merge(a::x,y);
You seem reasonably close. A few hints/remarks:
1) Aesthetically, using nil in one line and [] in others seems odd. Either use all nil or use all []
2) Since the input are lists of lists, in x::y::z, the identifiers x and y would be lists of integers, rather than individual integers. Thus, x<y wouldn't make sense. You can't compare lists of integers using <.
3) Your problem description strongly suggests that the inner-lists are all 1-element lists. Thus you could use the pattern [x]::[y]::z to allow you to compare x and y. In this case, x#y could be replaced by [x,y]
4) If the inner lists are allowed to be of arbitrary size, then your code needs major revision and would probably require a full-fledged sort function to sort the result of concatenating pairs of inner lists. Also, in this case, the single list in the one inner list case should probably be sorted.
5) You have a typo: mergeP isn't mergePass.
On Edit:
If the sublists are each sorted (and the name of the overall function perhaps suggests this) then you need a function called e.g. merge which will take two sorted lists and combine them into a single sorted list. If this is for a class and you have already seen a merge function as an example (perhaps in a discussion of merge-sort) -- just use that. Otherwise you will have to write your own before you write this function. Once you have the merge function, skip the part of comparing x and y and instead have something as simple as:
| mergePass (xs::ys::zss) = (merge xs ys) :: mergePass zss
If the sublists are not merged, then you will need a full-fledged sort in which case you would use something like:
| mergePass (xs::ys::zss) = sort(xs # ys) :: mergePass zss
Is there a more efficient way to update an element in a list in Elm than maping over each element?
{ model | items = List.indexedMap (\i x -> if i == 2 then "z" else x) model.items }
Maybe Elm's compiler is sophisticated enough to optimize this so that map or indexedMap isn't unnecessarily copying over every element except 1. What about nested lists?
Clojure has assoc-in to update an element inside a nested list or record (can be combined too). Does Elm have an equivalent?
More efficient in terms of amount of code would be (this is similar to #MichaelKohl's answer):
List.take n list ++ newN :: List.drop (n+1) list
PS: if n is < 0 or n > (length of list - 1) then the new item will be added before or at the end of the list.
PPS: I seem to recall that a :: alist is slightly better performing than [a] ++ alist.
If you mean efficient in terms of performance/ number of operations:
As soon as your lists get large, it is more efficient to use an Array (or a Dict) instead of a List as your type.
But there is a trade-off:
Array and Dict are very efficient/ performant when you frequently retrieve/ update/ add items.
List is very performant when you do frequent sorting and filtering and other operations where you actually need to map over the entire set.
That is why in my code, List is what I use a lot in view code. On the data side (in my update functions) I use Dict and Array more.
Basically, an Elm list is not meant for such a use-case. Instead, consider using an Array. Array contains a set function you can use for what is conceptually an in-pace update. Here's an example:
import Html exposing (text)
import Array
type alias Model = { items : Array.Array String }
model =
{ items = Array.fromList ["a", "b", "c"]
}
main =
let
m = { model | items = Array.set 2 "z" model.items }
z = Array.get 2 m.items
output = case z of
Just n -> n
Nothing -> "Nothing"
in
text output -- The output will be "z"
If for some reason you need model.items to be a List, note that you can convert back and forth between Array and List.
I'm not overly familiar with Elm, but given that it's immutable by default, I'd assume it uses structural sharing for its underlying data structures, so your concern re memory may be unfounded.
Personally I think there's nothing wrong with your approach posted above, but if you don't like it, you can try something like this (or List.concat):
List.take n list ++ newN :: List.drop (n+1)
I'm definitely not an Elm expert, but a look at Elm's List documentation did not reveal any function to update the element at a given index in a list.
I like Michael's answer. It's quite elegant. If you prefer a less-elegant, recursive approach, you can do something like the following. (Like I said, I'm not an Elm expert, but hopefully the intention of the code is clear if its not quite right. Also, I don't do any error handling.)
updateListAt :: List a -> Int -> a -> List a
updateListAt (head :: tail) 0 x = x :: tail
updateListAt (head :: tail) i x = head :: (updateListAt tail (i - 1) x)
However, both the runtime and space complexity will be O(n) in both the average and worst cases, regardless of the method used. This is a consequence of Elm's List being a single-linked list.
Regarding assoc-in, if you look at the Clojure source, you'll see that assoc-in is just recursively defined in terms of assoc. However, I think you'd have trouble typing it for arbitrary, dynamic depth in Elm.
Alright, so I was making some tests to get familiar with Scala, and wanted to see if I could make lists Java style rather than the fancy way you'd do it in Scala...
I know that you can do it like this: val lst = List.range(0, 100, 1) but I just wanted to see what java style would look like in scala
Alright so here's what I did:
var lst = List[Int]()
for(i <- 0 until 100) {
lst = lst :: i // here's where it complains
}
for some reason scala, or at least the scala ide for eclipse doesn't like that I append using infix notation, a-la lst :: i it wants me to do it like this: lst.::(i) otherwise it says :: isn't defined or something, it's not the first time it's happened either...
so can anyone here explain why it does that, or is it just a case of bad implementation in eclipse and thus something I have to live with
This isn't a problem with infix notation. Rather, it's because method names ending with : are applied as
a ??: b
b.??:(a)
So you simply have your arguments backwards.
lst = i :: lst
will work fine.
(Of course, you then have the issue that lists act like stacks, so you need to push the numbers on in reverse order.)
In Scala, a List is of immutable length. It can work like a LIFO (last in, first out) structure, but it cannot behave like a Java ArrayList.
You are doing this:
val lst = List[Int]()
which gives your lst a size of 0. It means you can't really do anything with it.
For a mutable collection, use ListBuffer.
Also, the :: operator is right associative, which means it will be called on the object found on the right side of the operator.
val lst = ListBuffer[Int]()
for (i <- 0 until 100) {
lst += i // will add to the tail.
}
I have a list of lists like so:
[["BBBBBBBB",
"BWFFFPFGB",
"BWFFFPFGB",
"BWFFMPFGB",
"BWFFFPF_B",
"BWFFFPF6B",
"BBBBBBB"]]
I've done a little research and have found out how to access individual elements using the !! operator. But when it comes to searching for a certain element 'M' I'm not sure how to go about that. My friend said I need to use something like (x:xs):xss on a list, but when I try this in the WinGHCi haskell program I get this.
Prelude> let list = [["BBBBBBBB",
"BWFFFPFGB",
"BWFFFPFGB",
"BWFFMPFGB",
"BWFFFPF_B",
"BWFFFPF6B",
"BBBBBBB"]]
Prelude> head(x:xs):xss
<interactive>:192:2: Not in scope: `x'
<interactive>:192:4: Not in scope: `xs'
<interactive>:192:8: Not in scope: `xss'
I understand that I declare the name as list and not x:xs but even when I declare it as x:xs I still get the errors. I'm probably still a little new to haskell to really understand what to do so I may be going about this way wrong.
I've looked here Replace individual list elements in Haskell? because eventually I want to replace the M with something different but I'm not completely sure how I would implement that.
Any help/guidance is appreciated, thanks!
First let's see how to replace a W with M
charWM :: Char -> Char
charWM 'W' = 'M' -- If you see W, put M.
charWM x = x -- If you see anything else, put it back as is.
You can rewrite that function how you like by adding other letter transformations.
Now let's make that work over a list. There's a great function map :: (a ->b) -> [a] -> [b] that lets you apply a function on every element on a list.
stringWM :: String -> String
stringWM xs = map charWM xs -- do charWM to everything in xs.
For example stringWM "QWERTY WILL WIN" = "QMERTY MILL MIN"
Next we can do that to a list of lists:
lolWM :: [String] -> [String]
lolWM xss = map stringWM xss
(String is a type synonym for [Char].)
Let's test that out in ghci:
*Main> list'
["BBBBBBBB","BWFFFPFGB","BWFFFPFGB","BWFFMPFGB","BWFFFPF_B","BWFFFPF6B","BBBBBBB"]
*Main> lolWM list'
["BBBBBBBB","BMFFFPFGB","BMFFFPFGB","BMFFMPFGB","BMFFFPF_B","BMFFFPF6B","BBBBBBB"]
All good.
Your example wasn't exactly list', it was [list'] which has 1 element, so to work on that we'd need to map lolWM. Often we wouldn't bother writing stringWM or lolWM and go directly to lists of lists of lists, if that's what we needed:
lololWM = (map.map.map) charWM
map.map.map means map the map of the map. You can allow that to blow your mind a little, or you can just say list of list of list of Char, so map map map - one map per list level.
In the future, maybe you'll want to replace W with Strings instead of characters.
rewriteChar :: Char -> String
rewriteChar 'W' = "--^--"
rewriteChar x = [x] -- put x in a list to make it a string
This time, map isn't enough: map rewriteChar "QWERTY WILL WIN" gives
["Q","--^--","E","R","T","Y"," ","--^--","I","L","L"," ","--^--","I","N"]
We could use concat on that to flatten it into a single list, but it's more fun to do
rewriteString = concatMap rewriteChar
So now rewriteString "QWERTY WILL WIN" give us "Q--^--ERTY --^--ILL --^--IN".
For more mindblowing things to try, there's "QWERTY WILL WIN" >>= rewriteChar and "Hello Mum" >>= \x -> [x,x,x]
First of all, virtually all "variables" in Haskell are immutable, so there's no "changing a list", there are modified copies.
Second, you need to find an element by some criteria. To do that, you need to traverse a list. - This can be done using recursion. Filtering can be done using a function passed as an argument of your traversing function (this function must take an element and return a boolean value).
Try to put the above together and make your own function. Start with a type signature, it shows what you want to do: to take a list of Char (it's better to generalize to a generic type) and a function which possibly changes an element and return a modified list:
replaceFunc :: (Char -> Char) -> String -> String
Also, read http://www.haskell.org/haskellwiki/How_to_work_on_lists , there's a hint there how to apply some function to specific elements only.
I am given an array of Char and have to translate it to Moves (as shown below)
data Move = N | S | W | E | X
newtype Moves = Moves [Move]
createMoves:: [Char]-> Moves
createMoves (x:xs) = if xs==[] then Moves [createMove(x)]
else Moves [createMove (x)]
createMove:: Char-> Move
createMove (x) = if x=='N' then N
else if x=='S' then S
else if x=='W' then W
else if x=='E' then
else X
However, I am only succeeding in getting the first item of the list. I have tried a number of ways to make createMoves recursive but I can't get it right. Could you please guide me?
Branches of your if statement are the same, so it does nothing.
When programming recursive functions, there are two cases.
The basic one, you should declare createMoves [] = [].
The recursive is a little more complicated; basically, for each x you create a move that is the first element appended to a list built using a recursive call on xs.
A simpler way is to use the map function. You can also look at its implementation.
By the way, for createMove you could use pattern matching instead of many ifs.
Your problem seems to be centering on combining the result of the recursive call on xs with the result of createMove x. So, let's just introduce a helper function which is going to take care of that!
createMoves:: [Char]-> Moves
createMoves (x:xs) = if xs==[] then Moves [createMove x]
else createHelper (createMove x) (createMoves xs)
Now, what should the type of createHelper be? Its first argument is a Move and the second is a Moves, and it should put the first argument in front of the list of Moves contained in the second, and 'repack' it in a value of type Moves. To get at the list of Moves you need to use pattern matching, like so:
createHelper :: Move -> Moves -> Moves
createHelper m (Moves ms) = Moves (m:ms)
That should do the trick, but all this matching on the Moves constructor and then reapplying it is a bit silly, and potentially inefficient. A better approach is to convert the [Char] one-by-one to [Move] and only at the end tacking the Moves constructor on. That leads to something like (still in keeping with your original idea):
createMoves :: [Char] -> Moves
createMoves cs = Moves (createMoveList cs)
createMoveList :: [Char] -> [Move]
createMoveList (x:xs) = if xs == [] then [] else createMove x : createMoveList xs
createMoveList is a pattern that comes up very often in Haskell, namely that of applying a function (in this case, createMove) to each element in a list. This is the essence of the map function (which I'm sure you'll get to very soon in your lessons, if you haven't already!).
If you use that, you can also get rid of the problem that createMoves fails when given an empty list. So the solution I would go with is:
createMoves :: [Char] -> Moves
createMoves cs = Moves (map createMove cs)
or
createMoves = Moves . map createMove
but that's another story!
Your createMoves function only operates on one element of the list it's given.
Try using the map function. On other words, start your function with:
createMoves list = Moves (map
[...]
You may wish to use Guards (i.e. |) instead of if, then and else.
First, you should remove the newtype statement; if you want the list to print, just have the Move type derive Show.
Next, you can remove the explicit recursion in the createMoves function by using map. For future reference, you can look for functions by name and type signature on Hoogle.
Finally, you can use pattern matching to eliminate all the equality tests against constants. An irrelevant example using the Move type is
isN :: Move -> Bool
isN N = True
isN _ = False
Note that the _ character means "ignore this value". If you haven't covered pattern matching yet, then guards might still be better than nested ifs.