Reputation: 1065
I've created the following data types.
{- Data declaration predefined in Haskell -}
data Maybe_ a = Nothing_ | Just_ a deriving( Show )
{- Array declaration -}
data Array_ a = A [ ( Int, Maybe_ a ) ] deriving( Show )
Now, I'd like to create an update function that - given an index, an Array_
and a new value - update the value of the array at the given index.
Here's the signature of the function ...
update :: ( Int, Array_ a, a ) -> Array_ a
... and here's the complete function
update :: ( Int, Array_ a, a ) -> Array_ a
update( i, A[], new_value ) = error( ( show i ) ++ " is not an index" )
update( i, A( ( j, Just_ x ):l ), new_value )
| i == j = A( ( j, Just_ new_value ):l )
| i /= j = update ( i, A l, new_value )
The issue occurs at the last line of the function. It's a recursive call to the end of the list, but it doesn't keep the previously consider elements of the array.
I was thinking of using either the ++
operator or the :
one, but both of the time I get an error.
... i /= j = ( j, Just_ x ):update ( i, A l, new_value )
... i /= j = A[( j, Just_ x )] ++ update ( i, A l, new_value )
How can I handle this differently?
Upvotes: 0
Views: 52
Reputation: 476503
First of all it is a bit un-Haskell to work with tuples, usually you define separate parameters, like:
update :: Int -> Array_ a -> a -> Array_ a
So that you can easily work with an update 5
function where you will later provide additional arguments.
Nevertheless the problem is that in your last branch:
| i /= j = update i (A l) new_value
you thus perform a recursive call, but the result of that recursive call will be the final result. In order to solve this issue, you simply prepend the item that you inspected, and did not match the index. Since you do this for all index failure, all indices that do not match will be in the final result, so:
| i /= j = (j, Just_ x) : update i (A l) new_value.
So now we obtain:
update :: Int -> Array_ a -> a -> Array_ a
update i (A []) new_value = error( ( show i ) ++ " is not an index" )
update i (A ((j, Just_ x):l)) new_value
| i == j = A ((j, Just_ new_value):l)
| i /= j = let A t = update i (A l) new_value in A ((j, Just_ x):t)
That being said there are still some things we can do to improve our function:
@
to prevent us from repacking the head of the list.==
and /=
. It is better to use otherwise
(an alias of True
in the last branch (this is more or less equivalent with else
in Java).hlint
.If we take the above comments into account, an - in my opinion - more elegant function would be:
update :: Int -> Array_ a -> a -> Array_ a
update i (A []) _ = error $ show i ++ " is not an index"
update i (A (h@(j,Just_):l)) new_value
| i == j = A ((j, Just_ new_value):l)
| otherwise = let A t = update i (A l) new_value in A (h:t)
Finally there is still a case unresolved: what to do if there are Nothing_
s in your list. If you don't care whether the value is a Just_ x
or a Nothing_
, you can rewrite it like:
update :: Int -> Array_ a -> a -> Array_ a
update i (A []) _ = error $ show i ++ " is not an index"
update i (A (h@(j,_):l)) new_value
| i == j = A ((j, Just_ new_value):l)
| otherwise = let A t = update i (A l) new_value in A (h:t)
Upvotes: 3