I recently started Erlang, and I notice I constantly get "Warning: variable X is unused" while compiling. For example, take the following function, which finds the maximum element in a list:
max([Head|Tail]) ->
max(Head,Tail).
max(Element,[Head | Tail]) when Element < Head ->
max(Head,Tail);
max(Element,[Head | Tail]) ->
max(Element, Tail);
max(Element,[]) ->
Element.
The compiler warns me that in the 3rd case of the function, Head is unused. How can the function be written without Head?
If you name a variable _ instead of Name (e.g. _ instead of Head) the variable will not be bound, and you will not get a warning.
If you name a variable _Name instead of Name (e.g. _Head instead of Head) the variable will be bound, but you will still not get a warning. Referencing a variable beginning with _ in the code is considered very bad practice.
It is recommended to keep the name of the variable to improve the readability of the code (e.g. it is easier to guess what _Head was intended for than just _).
This should suppress the warning without being confusing:
max(Element,[_Head | Tail]) ->
max(Element, Tail);
max([Head|Tail]) ->
max(Head,Tail).
max(Element,[Head | Tail]) when Element < Head ->
max(Head,Tail);
max(Element,[_| Tail]) ->
max(Element, Tail);
max(Element,[]) ->
Element.
Should do the trick. The reason being that replacing 'Head' with '_' is syntax for saying that a parameter will be placed there, but I don't need it.
Related
I've started learning F# and following in the footsteps of example problems I've written my own statement. It's simple enough, but I'm getting an error that doesn't exist in similar recursion examples.
My function replace takes a list of integers, an swapVal integer and a newVal integer. It then recurses through the list and changes any 'swapVal' to 'newVal'.
let original = [1;3;1;4;1;6;1;9]
let rec replace list origVal newVal =
match list with //look at list
| [] -> [] //when ls empty, return empty list
| head :: tail when head = origVal -> newVal :: replace tail origVal newVal
//when list is a head attached to a tail, if head = origVal,
//call replace on tail and appead the newVal
|_ :: tail -> replace tail origVal newVal
//head not equal to original value, call replace tail and return result
Calling replace original 1 5 I'm getting the following error Script.fsx(144,9): error FS0039: The value or constructor 'original' is not defined. Searching online like here hasn't turned up any solutions. Even O'Reilly's programming F# says that it could be a scoping problem, but there's no way that scope is my error.
I feel like it could be that f# is typing my arguments incorrectly, but I don't know enough about f# to know how it types. I would cast the arguments to make sure, but I read that it's not possible.
Does anyone see any immediate errors?
we have mapOptional from the NICTA course:
mapOptional :: (a -> b) -> Optional a -> Optional b
mapOptional _ Empty = Empty
mapOptional f (Full a) = Full (f a)
When matching f we obviously use that function that was passed, what about the Empty? and what about Full?
There is nothing in Haskell that lets you observe whether the two Emptys are the same Empty or not, and no guarantees about what an implementation must do with that code in that regard.
That said, in GHC, nullary constructors for a given parameterized type are shared across all parameterizations; so there is just one Empty in the whole program, and just one [], and so forth.
They can't be the same Empty, the argument has the type Optional a and the output has the type Optional b. When I try to force some sort of reuse, I will typically use something of the type
mapOptional _ a#Empty = a
This won't compile, and I don't think that's implementation dependent.
Suppose I have to update a list with each call to a function, such that, the previous element of the list are preserved.
Here is my attempt:
local
val all_list = [];
in
fun insert (x:int) : string = int2string (list_len( ((all_list#[x])) ) )
end;
The problem is that each time I call to insert, I get the output "1", which indicates that the list is initiated to [] again.
However I was expecting output of "1" for the first call to insert, and "2" for the second call,...etc.
I am not able to come with a workaround. How should it be done?
You need to use side-effects.
Most of the time functional programmers prefer to use pure functions, which don't have side effects. Your implementation is a pure function, so it will always return the same value for the same input (and in your case it returns the same value for any input).
You can deal with that by using a reference.
A crash course on references in Standard ML:
use ref to create a new reference, ref has type 'a -> 'a ref, so it packs an arbitrary value into a reference cell, which you can modify later;
! is for unpacking a reference: (!) : 'a ref -> 'a, in most imperative languages this operation is implicit, but not in SML or OCaml;
(:=) : 'a ref * 'a -> unit is an infix operator used for modifying references, here is how you increment the contents of an integer reference: r := !r + 1.
The above gives us the following code (I prepend xs onto the list, instead of appending them):
local
val rxs = ref []
in
fun insert (x:int) : string =
(rxs := x :: !rxs;
Int.toString (length (!rxs)))
end
Values are immutable in SML. insert is defined in a context in which the value of all_list is [] and nothing about your code changes that value.
all_list#[x]
doesn't mutate the value all_list -- it returns a brand new list, one which your code promptly discards (after taking its length).
Using reference types (one of SML's impure features) it is possible to do what you seem to be trying to do, but the resulting code wouldn't be idiomatic SML. It would break referential transparency (the desirable feature of functional programming languages where a function called with identical inputs yields identical outputs).
I'm learning Erlang from the very basic and have a problem with a tail recursive function. I want my function to receive a list and return a new list where element = element + 1. For example, if I send [1,2,3,4,5] as an argument, it must return [2,3,4,5,6]. The problem is that when I send that exact arguments, it returns [[[[[[]|2]|3]|4]|5]|6].
My code is this:
-module(test).
-export([test/0]).
test()->
List = [1,2,3,4,5],
sum_list_2(List).
sum_list_2(List)->
sum_list_2(List,[]).
sum_list_2([Head|Tail], Result)->
sum_list_2(Tail,[Result|Head +1]);
sum_list_2([], Result)->
Result.
However, if I change my function to this:
sum_list_2([Head|Tail], Result)->
sum_list_2(Tail,[Head +1|Result]);
sum_list_2([], Result)->
Result.
It outputs [6,5,4,3,2] which is OK. Why the function doesn't work the other way around([Result|Head+1] outputing [2,3,4,5,6])?
PS: I know this particular problem is solved with list comprehensions, but I want to do it with recursion.
For this kind of manipulation you should use list comprehension:
1> L = [1,2,3,4,5,6].
[1,2,3,4,5,6]
2> [X+1 || X <- L].
[2,3,4,5,6,7]
it is the fastest and most idiomatic way to do it.
A remark on your fist version: [Result|Head +1] builds an improper list. the construction is always [Head|Tail] where Tail is a list. You could use Result ++ [Head+1] but this would perform a copy of the Result list at each recursive call.
You can also look at the code of lists:map/2 which is not tail recursive, but it seems that actual optimization of the compiler work well in this case:
inc([H|T]) -> [H+1|inc(T)];
inc([]) -> [].
[edit]
The internal and hidden representation of a list looks like a chained list. Each element contains a term and a reference to the tail. So adding an element on top of the head does not need to modify the existing list, but adding something at the end needs to mutate the last element (the reference to the empty list is replaced by a reference to the new sublist). As variables are not mutable, it needs to make a modified copy of the last element which in turn needs to mutate the previous element of the list and so on. As far as I know, the optimizations of the compiler do not make the decision to mutate variable (deduction from the the documentation).
The function that produces the result in reverse order is a natural consequence of you adding the newly incremented element to the front of the Result list. This isn't uncommon, and the recommended "fix" is to simply list:reverse/1 the output before returning it.
Whilst in this case you could simply use the ++ operator instead of the [H|T] "cons" operator to join your results the other way around, giving you the desired output in the correct order:
sum_list_2([Head|Tail], Result)->
sum_list_2(Tail, Result ++ [Head + 1]);
doing so isn't recommended because the ++ operator always copies it's (increasingly large) left hand operand, causing the algorithm to operate in O(n^2) time instead of the [Head + 1 | Tail] version's O(n) time.
I'm working on a p2p app that uses hash trees.
I am writing the hash tree construction functions (publ/4 and publ_top/4) but I can't see how to fix publ_top/4.
I try to build a tree with publ/1:
nivd:publ("file.txt").
prints hashes...
** exception error: no match of right hand side value [67324168]
in function nivd:publ_top/4
in call from nivd:publ/1
The code in question is here:
http://github.com/AndreasBWagner/nivoa/blob/886c624c116c33cc821b15d371d1090d3658f961/nivd.erl
Where do you think the problem is?
Thank You,
Andreas
Looking at your code I can see one issue that would generate that particular exception error
publ_top(_,[],Accumulated,Level) ->
%% Go through the accumulated list of hashes from the prior level
publ_top(string:len(Accumulated),Accumulated,[],Level+1);
publ_top(FullLevelLen,RestofLevel,Accumulated,Level) ->
case FullLevelLen =:= 1 of
false -> [F,S|T]=RestofLevel,
io:format("~w---~w~n",[F,S]),
publ_top(FullLevelLen,T,lists:append(Accumulated,[erlang:phash2(string:concat([F],[S]))]),Level);
true -> done
end.
In the first function declaration you match against the empty list. In the second declaration you match against a list of length (at least) 2 ([F,S|T]). What happens when FullLevelLen is different from 1 and RestOfLevel is a list of length 1? (Hint: You'll get the above error).
The error would be easier to spot if you would pattern match on the function arguments, perhaps something like:
publ_top(_,[],Accumulated,Level) ->
%% Go through the accumulated list of hashes from the prior level
publ_top(string:len(Accumulated),Accumulated,[],Level+1);
publ_top(1, _, _, _) ->
done;
publ_top(_, [F,S|T], Accumulated, Level) ->
io:format("~w---~w~n",[F,S]),
publ_top(FullLevelLen,T,lists:append(Accumulated,[erlang:phash2(string:concat([F],[S]))]),Level);
%% Missing case:
% publ_top(_, [H], Accumulated, Level) ->
% ...