I have a List a and a Maybe a. I want to append the maybe value if it is Just a but do nothing if it is Nothing.
This is what I am currently using:
aList ++ case maybeValue of
Just value ->
[ value ]
Nothing ->
[]
Is there a better (more idiomatic) way of doing this?
Note that prepending is fine too if there is a cleaner way of doing that instead. The list order does not matter.
From Chad's suggestion that prepending is cheaper:
prependMaybe : List a -> Maybe a -> List a
prependMaybe list maybe =
case maybe of
Just value ->
value :: list
Nothing ->
list
I think you can use Maybe.map List.singleton yourMaybe |> Maybe.withDefault [].
Here you have a complete example:
appendMaybe : List a -> Maybe a -> List a
appendMaybe list maybe =
Maybe.map List.singleton maybe
|> Maybe.withDefault []
|> (++) list
You can try it on Ellie
If you're going for conciseness, you could use Maybe.Extra.unwrap from the elm-community/maybe-extra package:
import Maybe.Extra exposing (unwrap)
consMaybe : List a -> Maybe a -> List a
consMaybe list =
unwrap list (flip (::) list)
appendMaybe : List a -> Maybe a -> List a
appendMaybe list =
unwrap list ((++) list << List.singleton)
If you really want to go crazy, you can create your own infix operators:
infixr 5 ::?
(::?) = flip consMaybe
infixr 5 ++?
(++?) = appendMaybe
This allows the following:
Nothing ::? [2, 3, 4] == [2, 3, 4]
Just 1 ::? [2, 3, 4] == [1, 2, 3, 4]
[2, 3, 4] ++? Nothing == [2, 3, 4]
[2, 3, 4] ++? Just 5 == [2, 3, 4, 5]
Now, whether the infix versions are idiomatic Elm, that's up for debate. If it's something you use a lot, perhaps it's worth it, but most Elm guides urge you to avoid infix operators because they hinder discoverability.
In the end, your original example has the benefit of being readable and probably more readily understandable, since fewer people will be familiar with unwrap. The only suggestion would be that if order truly doesn't matter, then prepending an item to a list is going to be faster than concatenating lists.
Related
I'm a Haskell beginner,
I have a function
func :: Num a => [a] -> [a]
func [] = []
func (x:xs) = x + func xs
Each recursion I want to append the value to a list for my output. This function will sum consecutive indexes in a list so that the input [1, 2, 3, 4] produces [1, 3, 6, 10].
How do I append the value generated each time to my list?
Your problem here isn't how to append, but rather how to calculate the value in the first place. Each item needs to be substituted with a sum of itself with all the items preceding it.
Here is one way to do it:
Prelude> func (x:xs) = x:map (+ x) (func xs); func [] = []
Prelude> func [1, 2, 3, 4]
[1,3,6,10]
How does this work? We're given a list that starts with the element x and has the remaining elements xs. We want to increment every item in xs by x, after recursively applying the algorithm to xs.
This is what x:map (+ x) (func xs) does. It reads as "prepend x to the result of mapping every element in func xs through an increment by x".
E.g. for [1, 2, 3, 4], we want 1 to be added to every member of the result of recursively applying the algorithm to [2, 3, 4], then prepended. For [2, 3, 4] we want 2 to be ... to [3, 4]. And so on, until eventually for [4] we want 4 to be added and prepended to the result of applying the algorithm to [].
This is where our base case (func [] = []) kicks in: the algorithm is defined so that it returns an empty list unchanged. Hence func [4] is [4], func [3, 4] is [3, 7], and you keep incrementing and prepending until you get [1,3,6,10].
I think in this particular case, you could use scanl1 like:
scanl1 (+) [1,2,3,4] -- [1,3,6,10]
When iterating over lists, we often use folds, which is a way of reducing the list to a particular value.
There's also another type of operation, which is a fold that collects all results along the way, and that's called a scan (from the docs):
scanl = scanlGo
where
scanlGo :: (b -> a -> b) -> b -> [a] -> [b]
scanlGo f q ls = q : (case ls of
[] -> []
x:xs -> scanlGo f (f q x) xs)
So the scan takes three arguments: a function that takes two values and returns a value, a starter value, and a list of values.
The scan will then return a list.
Thus, what you need is a function that takes two values and returns something of the same type as the first (it's okay if both are the same). Binary addition would work here: +.
You also need a value to start off with (the b, which is the second argument to our function), and 0 is the identity for integer addition, so we should use that.
Finally, we pass your list to get the result.
Try to figure out how to write you function as a fold and then as a scan and you will discover the answer.
All I've been able to find in the documentation that are relevant are ++ and concat.
I thought at first doing the following would give me what I wanted:
[1, 3, 4] ++ [4, 5, 6]
but as you know that just gives [1, 2, 3, 4, 5, 6].
What would I need to do to take in [1, 2, 3] and [4, 5, 6] and get out [[1, 2, 3], [4, 5, 6]]?
As mentioned in comments, a function to take two lists and combine them into a new list can be defined as:
combine :: [a] -> [a] -> [[a]]
combine xs ys = [xs,ys]
This function can't be applied multiple times to create a list of an arbitrary number of lists. Such a function would take a single list and a list of lists and it would add the single list to the list of lists, so it would have type:
push :: [a] -> [[a]] -> [[a]]
This is just (:), though:
push = (:)
As also mentioned in the comments, the value [x,y] can also be written as x : y : [].1 Since both cases can be done with (:), I would guess that what you really want to use is (:), sometimes consing onto [] and sometimes onto a non-empty list.
1 In fact, [x,y] is just syntactic sugar for x:y:[].
think about what the (++) operator does: it concatenates Lists, it does not construct them. This is how it concatenates text Strings into a new String (and not a list of Strings), since Strings are lists of Chars. to construct a new List out of Lists you use (:) like so:
[1,2,3]:[4,5,6]:[]
where youre adding each list as an element of a new list.
the Nested List can exist in Scheme, but is it legal to use nested-list in SML? or we can only use simple list in SML?
and if legal,
1) how to check wether the two input list have the same list structure. algorithm the atoms in the list are not equal.
2) Whatever the deep of the input list, how to delete all the atoms in the nested-list that equals to the input value: a. should use the original list and not create a new list.
There's no problem in having nested lists in Standard ML. For an example:
val foo = [ [1, 2, 3], [4, 5], [6] ]
is an example of an int list list, i.e., a list of lists of integers.
As for your additional questions.
1
If by same structure you mean whether the sublists contain the same number of elements, i.e, you want
val bar = [ [34, 4, 6], [2, 78], [22] ]
val baz = [ [1], [4, 6, 2], [3, 6] ]
val cmp_foo_bar = structureEq (foo, bar) (* gives true, since the lengths of the sublists match up *)
val cmp_foo_baz = structureEq (foo, baz) (* gives false, since they don't *)
Then you can simply make a recursive function on the lists, that compares the length of each sublist in turn.
Note, if the lists are nested more than once, you'll need a function for each level. (i.e., one for 'a list lists, one for 'a list list lists, etc.
2
You cannot make a function that "however deep the input list" does something to the elements in the list. The type system will not let you do this. This is similar to how you cannot make the following list:
val illegal_list = [ [1, 2], [ [1, 4], [2, 3] ] ]
This is due to a list only being allowed to contain one type of elements, so if you have an 'a list list, each element in the list must be an 'a list. You cannot have 'as directly.
You'll have to settle on how nested the lists are, and make a function specific to that depth.
There is no problem with nesting lists in SML, e.g. [[1, 2], [3, 4]] works just fine.
However, I suspect you actually mean something more general, namely the ability to nest "lists" in heterogeneous ways: [[1, [3]], 2]. This is not legal as such in SML. However, this is because such a thing is not really a list, it is a tree.
You can define trees easily as well, but you need a more general type definition than the one for list:
datatype 'a tree = L of 'a | T of 'a tree list
Then T[T[L 1, T[L 3]], L 2] is a representation of the "list" above. A function for computing the depth (or height) of such a tree looks like
fun depth (L _) = 0
| depth (T ts) = 1 + max (List.map depth ts)
where max needs to be defined in the obvious manner.
I am trying to write a function like this:
updateMatrix:: [[a]] -> a -> (x, y) ->[[a]]
This is supposed to take in a list of lists such as:
[ [1, 2, 3, 4],
[5, 6, 7, 8]]
and put the given element at the specified coordinates, so, given:
[ [1, 2, 3, 4],
[5, 6, 7, 8]] 9 (0, 1)
it should return
[ [1, 9, 3, 4],
[5, 6, 7, 8]]
I can't figure out how to do this without having to rebuild the whole matrix, please help!
You need to rebuild the matrix every time. So as long as you don't need high performance computing, you could use this legible implementation:
replace :: (a -> a) -> Int -> [a] -> [a]
replace f 0 (x:xs) = (f x):xs
replace f i (x:xs) = x : replace f (i-1) xs
replace f i [] = []
replace2D :: (a -> a) -> (Int, Int) -> [[a]] -> [[a]]
replace2D f (x,y) = replace (replace f y) x
Your function would be:
updateMatrix ll x c = replace2D (const x) c ll
Here's an implementation:
updateMatrix :: [[a]] -> a -> (Int, Int) -> [[a]]
updateMatrix m x (r,c) =
take r m ++
[take c (m !! r) ++ [x] ++ drop (c + 1) (m !! r)] ++
drop (r + 1) m
But maybe this "rebuilds the whole matrix" as you say? Note that
lists are not mutable in Haskell, so you can't destructively update
one entry, if that's what you would mean by not "rebuilding the whole
matrix".
Here’s a short one:
replace p f xs = [ if i == p then f x else x | (x, i) <- zip xs [0..] ]
replace2D v (x,y) = replace y (replace x (const v))
Now you can use it exactly like you wanted:
λ → let m = [[1, 2, 3, 4], [5, 6, 7, 8]]
λ → replace2D 9 (0, 1) m
[[1,2,3,4],[9,6,7,8]]
As others already said,
This approach is of course rather slow, and only makes sense if the structure is more complex than the lists are long. There’s easy documentation about the internal structure and complexity of things in Haskell out there.
Think of m as a pointer to a linked list of pointers, and you can see why it’s slower than a pure stream of bytes. There are better libs that use something closer to the latter.
Haskell’s values are immutable because there are no side-effects. Which is good for reliability. So you can’t change m. You can only build something out of m.
Haskell can simulate mutable references, with the help of monads. Like IORef. But using it for this would be rather wrong. There are many other questions here on Stack Overflow, explaining its usage, pros and cons.
Being a purely functional language, Haskell requires you to return a "brand new" matrix when you update an item, so you need to rebuild the whole matrix indeed (if you're actually interested in matrix processing, cast a look at matrix library rather than implementing your own).
Beware, lists are not a good choice for such manipulations, but if you do it for educational purposes, start with implementing a function that "replaces" an element in [a], then use it twice (function composition can help there) in order to get your updateMatrix function. Here is an answer that can help you on your way.
Hi all im new to programming and im doing a problem for learning and enjoyment. Im a bit stuck at this point.. The problem is from Introduction to Programming using Sml 5.9
I want to split a list of [x1, x2, x3, ... ,xn] = ([x1, x3,....], [x2, x4,...])
This is what I have made so far:
fun split [] = []
| split (x1::x2::x3::x4::xs) = ([x1, x3], [x2, x4])::split xs
val test1split = split [1, 1, 2, 3];
From this I get:
[([1, 2], [1, 3])].... (I want a tuple with splitting list and not this obviously)
If there are more than 4 elements then the function doesn't work. Maybe I need a helper function to sort even and odd elements in a list first? I hope someone can help me with tracking my mind in the correct direction, until then I keep trying.
fun split [] = ([], [])
| split [x] = ([x], [])
| split (x1::x2::xs) =
let
val (ys, zs) = split xs
in
((x1::ys), (x2::zs))
end;
val test1split = split [1, 1, 2, 3, 5, 6] = ([1, 2, 5], [1, 3, 6])
val test2split = split [8, 7, 6, 5, 4, 3] = ([8, 6, 4], [7, 5, 3])
val test3split = split [8, 7] = ([8], [7])
val test4split = split [8] = ([8], [])
Solved it... Not completely sure how lol, need alot more practice to master it. Couldn't have done it without the pointers... Thx alot for the help Nick Barnes.
I'll try not to give too much away, but here are some tips:
You need two base cases - one for [], one for [x].
Your general case only needs to deal with two elements, not four (putting one in the first list, and one in the second)
At the moment, you've got split returning a list, rather than a tuple. The result of your first base case should be ([],[]).
In the general case, the recursive split xs will return a tuple (ys,zs). You need to extract these values, and build the resulting tuple in terms of ys, zs, x1 and x2.
(Edit) A couple of points on your revised solution:
You only need to deal with two elements at a time - the general case should be split x1::x2::xs
split [x,y] is handled by the general case - no need for another base case.
You're missing the recursive call! Elements are ending up in both lists because you're putting xs directly into both halves of your output - you need to split it first. Start with
let (ys, zs) = split xs in ...