Function to replace given element in list
Hi I'm trying to make a custom function to replace a given element in a list. Code: let i = elemIndex toReplace lst in case i of Just i -> let z = splitAt i lst x = fst z y = (snd z) in init x x ++ newNmr x ++ y Nothing -> [5] Error:
1) * Couldn't match expected type `[a] -> [a]' with actual type `[a]' * The function `init' is applied to two arguments, but its type `[a] -> [a]' has only one In the first argument of `(++)', namely `init x x' In the expression: init x x ++ newNmr x ++ y * Relevant bindings include y :: [a] (bound at C:\users\niel\desktop\test2.hs:41:21) x :: [a] (bound at C:\users\niel\desktop\test2.hs:40:21) z :: ([a], [a]) (bound at C:\users\niel\desktop\test2.hs:39:21) newNmr :: [a] (bound at C:\users\niel\desktop\test2.hs:34:30) lst :: [a] (bound at C:\users\niel\desktop\test2.hs:34:26) toReplace :: a (bound at C:\users\niel\desktop\test2.hs:34:16) (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds) 2) * Couldn't match expected type `[a] -> [a]' with actual type `[a]' * The function `newNmr' is applied to one argument, but its type `[a]' has none In the first argument of `(++)', namely `newNmr x' In the second argument of `(++)', namely `newNmr x ++ y' * Relevant bindings include y :: [a] (bound at C:\users\niel\desktop\test2.hs:41:21) x :: [a] (bound at C:\users\niel\desktop\test2.hs:40:21) z :: ([a], [a]) (bound at C:\users\niel\desktop\test2.hs:39:21) newNmr :: [a] (bound at C:\users\niel\desktop\test2.hs:34:30) lst :: [a] (bound at C:\users\niel\desktop\test2.hs:34:26) toReplace :: a (bound at C:\users\niel\desktop\test2.hs:34:16) (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)
I've tried a lot, but I always got an error. What am I doing wrong? Thanks!
Hi Niely, everything after the "in" in your "let in" is one expression. In other words all of this: init x x ++ newNmr x ++ y is being read as one line.. so init x x ++ newNmr x ++ y which is why the compiler is complaining that you are applying init to two values (init x x). I think what you want is actually something more like (init x) ++ [newNmr] ++ y assuming newNmr is a number and not already a list. I'm not entirely sure what you were trying to do there but you seem a bit confused.. "init x" on its own doesn't actually do anything; it computes a value but you aren't assigning it to anything here. If you wanted to keep those exact expressions you could instead do let x0 = init x x1 = x0 ++ newNmr in x1 ++ y and x1 ++ y would be the thing that actually gets return. In any case I am certainly no expert so hopefully someone else can explain this better than I can. On Tue, Jul 19, 2016 at 1:08 PM, Niely Boyken <niely.b0yk3n@gmail.com> wrote:
Hi
I'm trying to make a custom function to replace a given element in a list.
Code: let i = elemIndex toReplace lst in
case i of Just i -> let z = splitAt i lst x = fst z y = (snd z) in init x x ++ newNmr x ++ y
Nothing -> [5]
Error:
1) * Couldn't match expected type `[a] -> [a]' with actual type `[a]' * The function `init' is applied to two arguments, but its type `[a] -> [a]' has only one In the first argument of `(++)', namely `init x x' In the expression: init x x ++ newNmr x ++ y * Relevant bindings include y :: [a] (bound at C:\users\niel\desktop\test2.hs:41:21) x :: [a] (bound at C:\users\niel\desktop\test2.hs:40:21) z :: ([a], [a]) (bound at C:\users\niel\desktop\test2.hs:39:21) newNmr :: [a] (bound at C:\users\niel\desktop\test2.hs:34:30) lst :: [a] (bound at C:\users\niel\desktop\test2.hs:34:26) toReplace :: a (bound at C:\users\niel\desktop\test2.hs:34:16) (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds) 2) * Couldn't match expected type `[a] -> [a]' with actual type `[a]' * The function `newNmr' is applied to one argument, but its type `[a]' has none In the first argument of `(++)', namely `newNmr x' In the second argument of `(++)', namely `newNmr x ++ y' * Relevant bindings include y :: [a] (bound at C:\users\niel\desktop\test2.hs:41:21) x :: [a] (bound at C:\users\niel\desktop\test2.hs:40:21) z :: ([a], [a]) (bound at C:\users\niel\desktop\test2.hs:39:21) newNmr :: [a] (bound at C:\users\niel\desktop\test2.hs:34:30) lst :: [a] (bound at C:\users\niel\desktop\test2.hs:34:26) toReplace :: a (bound at C:\users\niel\desktop\test2.hs:34:16) (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)
I've tried a lot, but I always got an error. What am I doing wrong?
Thanks!
_______________________________________________ Haskell mailing list Haskell@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell
On Tue, Jul 19, 2016 at 4:08 PM, Niely Boyken <niely.b0yk3n@gmail.com> wrote:
let i = elemIndex toReplace lst in
case i of Just i -> let z = splitAt i lst x = fst z y = (snd z) in init x x ++ newNmr x ++ y
Nothing -> [5]
If I understand what you are trying to do correctly, a more idiomatic (and syntactically correct code) would be: case elemIndex toReplace lst of Just i -> let (xs,_:ys)=splitAt i lst in xs ++ (newNmr:ys) _ -> [5] In more general terms, replacing individual elements in standard lists is a very inefficient operation for large lists. Having you considered using a Zipper List which allows you to efficiently replace elements at a focal point (and also to traverse the list forward and backward efficiently)? An example implementation of a Zipper (just for Lists) is at https://hackage.haskell.org/package/ListZipper-1.2.0.2/docs/Data-List-Zipper..., but implementing your own is an easy and instructive exercise. Carl Edman
Using a zipper will not get you very far here. The best way would likely be to replace the list with a balanced search tree. Sticking with the list for now, your choice to replace the entire list with [5] if the sought element is not found seems a bit peculiar, and also leads to an inherent efficiency problem. First, let me show you what a more natural function might look like: replaceFirstMatching :: (a -> Maybe a) -> [a] -> [a] replaceFirstMatching _ [] = [] replaceFirstMatching p (x : xs) = case p x of Nothing -> x : replaceFirstMatching p xs Just x' -> x' : xs Taking a function as an argument rather than an element to replace and a replacement element avoids the risk of mixing up which is which, while also being somewhat more general. You can simulate the equality version using it, if you like: replaceFirstEqual :: Eq a => a -> a -> [a] -> [a] replaceFirstEqual toReplace replacement = replaceFirstMatching $ \x -> if x == toReplace then Just replacement else Nothing Now I mentioned that your [5] fall-back is problematic from an efficiency standpoint. The reason is that you don't know whether you'll find the element you desire until you find it or hit the end of the list. So you can't lazily produce bits of list as you go; you have to save up the pieces for a while. If you really want to do this, you certainly can, starting with a modified version of replaceFirstMatching that indicates whether it found the element: replaceFirstMatchingM :: (a -> Maybe a) -> [a] -> Maybe [a] replaceFirstMatchingM _ [] = Nothing replaceFirstMatchingM p (x : xs) = case p x of Nothing -> fmap (x:) replaceFirstMatchingM p xs Just x' -> Just (x' : xs) replaceFirstMatchingFallbackList :: (a -> Maybe a) -> [a] -> [a] -> [a] replaceFirstMatchingFallbackList p fallback xs = fromMaybe fallback (replaceFirstMatchingMaybe p xs) Note that, like replaceFirstEqual, replaceFirstMatchingFallbackList has arguments that are easily confused. On Tue, Jul 19, 2016 at 4:42 PM, Carl Folke Henschen Edman <carledman@gmail.com> wrote:
On Tue, Jul 19, 2016 at 4:08 PM, Niely Boyken <niely.b0yk3n@gmail.com> wrote:
let i = elemIndex toReplace lst in
case i of Just i -> let z = splitAt i lst x = fst z y = (snd z) in init x x ++ newNmr x ++ y
Nothing -> [5]
If I understand what you are trying to do correctly, a more idiomatic (and syntactically correct code) would be:
case elemIndex toReplace lst of Just i -> let (xs,_:ys)=splitAt i lst in xs ++ (newNmr:ys) _ -> [5]
In more general terms, replacing individual elements in standard lists is a very inefficient operation for large lists. Having you considered using a Zipper List which allows you to efficiently replace elements at a focal point (and also to traverse the list forward and backward efficiently)?
An example implementation of a Zipper (just for Lists) is at https://hackage.haskell.org/package/ListZipper-1.2.0.2/docs/Data-List-Zipper..., but implementing your own is an easy and instructive exercise.
Carl Edman
_______________________________________________ Haskell mailing list Haskell@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell
On Tue, Jul 19, 2016 at 6:13 PM, David Feuer <david.feuer@gmail.com> wrote:
Using a zipper will not get you very far here. The best way would likely be to replace the list with a balanced search tree.
That depends on the pattern of access and usage. For some a zippered list will outperform a self-balancing tree and vice versa. For others a zippered tree, or something else, will beat either. But when seeing the pattern of changing a single element in the middle of a list, a zippered list is the first improved data structure that comes to mind. Carl Edman
participants (4)
-
Carl Folke Henschen Edman -
David Feuer -
Niely Boyken -
Richard Fung