Erlang invalid guard expression - erlang

I was trying to write a program that counts up to the largest binary multiple. (A binary multiple of a number, e.g. N, is a multiple of the original number and is only made of the digits 0 and 1.)
However, the expression lists:max(hd(io_lib:format("~b", [N]))) < 50 throws illegal guard expression error. I know that this was due to calling a function not in the allowed functions of the guard sequences, but I don't really know how to avoid this error.
Can somebody explain how to avoid this error?
% X: Multiple to be checked
% N: The accumulator
countup(X, N) -> % io:write([X, N]),
if
lists:max(hd(io_lib:format("~b", [N]))) < 50 ->
N;
true ->
countup(X, N + X)
end.

Use a case instead of an if:
countup(X, N) -> % io:write([X, N]),
case lists:max(hd(io_lib:format("~b", [N]))) < 50 of
true ->
N;
false ->
countup(X, N + X)
end.
Or alternatively:
countup(X, N) -> % io:write([X, N]),
case lists:max(hd(io_lib:format("~b", [N]))) of
Max when Max < 50 ->
N;
_ ->
countup(X, N + X)
end.
In general, if is rarely used in Erlang. One of the most common uses for it is checking which range a value falls into:
if X < 10 ->
small;
X >= 10, X < 20 ->
medium;
X >= 20 ->
large
end
But in almost all other cases, a case will be more appropriate.
You can use integer_to_list(N) instead of hd(io_lib:format("~b", [N])). io_lib:format is guaranteed to return an "iolist" (a nested list of lists and strings), but the specific form of the result is not guaranteed, so your code might break in a future Erlang version if the implementation of io_lib:format changes.

Related

Pure pattern matching

I am building a function that counts of many times a character appears in a string after the nth position.
countCh ("aaabbbccc", 3, 'b')
val it: int = 2
In C, I would use an accumulator with a while loop. But I am trying to learn the F# functional face, where this approach is discouraged.
So I used guards to test few conditions and build the function:
let rec countCh (s:string, n:int, ch:char) =
match s, n, ch with
| (s, n, ch) when n > s.Length -> 0 //p1
| (s, n, ch) when n < 0 -> 0 //p2
| (s, n, ch) when s.[n] <> ch -> countCh(s, n + 1, ch) //p3
| (s, n, ch) when s.[n] = ch -> 1 + countCh(s, n + 1, ch) //p4
The coexistence of patterns 3 and 4 is problematic (impossible, I am afraid). Even if it compiles, I have not been able to make it work. How can this task functionally be handled?
First, the coexistence of these branches is not problematic. They don't conflict with each other. Why do you think that it's problematic? Is it because you get an "Incomplete pattern match" compiler warning? That warning does not tell you that the branches conflict, it tells you that the compiler can't prove that the four branches cover all possibilities. Or do you think that for some other reason? If you want your questions to be answered accurately, you'll have to ask them more clearly.
Second, you're abusing the pattern matching. Look: there are no patterns! The patterns in every branch are exactly the same, and trivial. Only guards are different. This looks very counterintuitively within a match, but would be plainly expressed with if..elif:
let rec countCh (s:string) n ch =
if n >= s.Length || n < 0 then 0
elif s.[n] = ch then 1 + countCh s (n + 1) ch
else countCh s (n + 1) ch
NOTE 1: see how I made the parameters curried? Always use curried form, unless there is a very strong reason to use tupled. Curried parameters are much more convenient to use on the caller side.
NOTE 2: your condition n > s.Length was incorrect: string indices go from 0 to s.Length-1, so the bail condition should be n >= s.Length. It is corrected in my code.
Finally, since this is an exercise, I must point out that the recursion is not tail recursion. Look at the second branch (in my code): it calls the function recursively and then adds one to the result. Since you have to do something with the result of the recursive call, the recursion can't be "tail". This means you risk stack overflow on very long inputs.
To make this into tail recursion, you need to turn the function "inside out", so to say. Instead of returning the result from every call, you need to pass it into every call (aka "accumulator"), and only return from the terminal case:
let rec countCh (s:string) n ch countSoFar =
if n >= s.Length || n < 0 then countSoFar
elif s.[n] = ch then countCh s (n+1) ch (countSoFar+1)
else countCh s (n+1) ch countSoFar
// Usage:
countCh "aaaabbbccc" 5 'b' 0
This way, every recursive call is the "last" call (i.e. the function doesn't do anything with the result, but passes it straight out to its own caller). This is called "tail recursion" and can be compiled to work in constant stack space (as opposed to linear).
I agree with the other answers, but I'd like to help you with your original question. You need to indent the function, and you have an off by one bug:
let rec countCh (s:string, n:int, ch:char) =
match s, n, ch with
| s, n, _ when n >= s.Length-1 -> 0 //p1
| s, _, _ when n < 0 -> 0 //p2
| s, n, ch when s.[n+1] <> ch -> countCh(s, n+2, ch) //p3
| s, n, ch when s.[n+1] = ch -> 1 + countCh(s, n+2, ch) //p4
I'd suggest to not write it yourself, but ask the library functions for help:
let countCh (s: string, n, c) =
s.Substring(n+1).ToCharArray()
|> Seq.filter ((=) c)
|> Seq.length
Or use Seq.skip, along with the fact that you can drop the conversion to character array:
let countCh (s: string, n, c) =
s
|> Seq.skip (n + 1)
|> Seq.filter ((=) c)
|> Seq.length

Overflow of an int in f#

I am working on some homework and we are supposed to be making a combination function in F#. I have got the factorial function down, but it seems to overflow once I get a big number to use factorial on. (Let's say 20) I understand I can use an int64 or a float, but that would change all the inputs on the code. What data type should I use?
let rec Fact (a:int)=
if (a = 0) then 1 else a*Fact(a-1);;
let combo (n:int) (k:int)=
if (n = 0) then 0 else (Fact n)/((Fact k)*(Fact (n-k)));;
On the code right now, when I do combo 20 5;; it gives me 2147. Which is clearly the wrong answer. I looked at the factorial function and when I put 20 in there it gave me a big negative number. Any help would be much appreciated. Thanks in advance.
First of all, if you want to avoid surprises, you can open the Checked module at the top of your file. This will redefine the numerical operators so that they perform overflow checks - and you'll get an exception rather than unexpected number:
open Microsoft.FSharp.Core.Operators.Checked
As Fyodor points out in the comment, you cannot fit factorial of 20 in int and you need int64. However, your combo function then performs division which will make the result of combo 20 5 small enough to fit into int.
One option is to change Fact to use int64, but keep combo as a function that takes and returns integers - you'll need to convert them to int64 before calling Fact and then back to int after performing the division:
let rec Fact (a:int64) =
if (a = 0L) then 1L else a * Fact(a-1L)
let combo (n:int) (k:int) =
if (n = 0) then 0 else int (Fact (int64 n) / (Fact (int64 k) * Fact (int64 (n-k))))
Now you can call combo 20 5 and you'll get 15504 as the result.
EDIT: As noted by #pswg in the other answer, int64 is also quite limited and so you'll need BigInteger for larger factorials. However, the same method should work for you with BigInteger. You can keep the combo function as a function that returns int by converting back from BigInteger to int.
You simply won't be able to do that with an 32-bit integer (int). A 64-bit integer will get you up to 20!, but will fail at 21!. The numbers just get too big, too quickly. To go any further than that you'll need to use System.Numerics.BigInteger (abbreviated bigint in F#).
The parameter can probably stay as an int to be reasonable, but you need to return a bigint:
let rec Fact (n : int) =
if n = 0 then bigint.One else (bigint n) * Fact (n - 1)
Or to be a little more idiomatic:
let rec Fact = function | 0 -> bigint.One | n -> (bigint n) * Fact (n - 1)
And now, in your Combo function, you'll need to use these bigint's internally for all math (thankfully the integer division is all you need in this case).
let Combo (n : int) (k : int) =
if n = 0 then bigint.Zero else (Fact n) / ((Fact k) * (Fact (n - k)))
If you really wanted to make Combo return an int, you can do that conversion here:
let Combo (n : int) (k : int) =
if n = 0 then 0 else (Fact n) / ((Fact k) * (Fact (n - k))) |> int
Examples:
Combo 20 5 // --> 15504
Combo 99 5 // --> 71523144 (would break if you used int64)
Edit: By rethinking your implementation of Combo you can get some big performance improvements out of this. See this question on Math.SE for the basis of this implementation:
let ComboFast (n : int) (k : int) =
let rec Combo_r (n : int) = function
| 0 -> bigint.One
| k -> (bigint n) * (Combo_r (n - 1) (k - 1)) / (bigint k)
Combo_r n (if (2 * k) > n then n - k else k)
A quick benchmark showed this to be significantly faster than the Fact-based version above:
Function Avg. Time (ms)
Combo 99 5 30.12570
ComboFast 99 5 0.72364

How to apply try and catch on a function?

I would like to know if it possible to apply a try catch expression on this function:
add(X, Y) ->
X + Y.
Here the user can provide a string instead of an integer.
Another example:
myfunction(X, Y) ->
case X == Y of
true -> X + Y;
false -> X * Y
end.
I just gave those example to know if it's possible or no and how?
Yes, you can certainly use try-catch in those functions. Here what it would look like:
add(X,Y) ->
try X + Y of
Z ->
Z
catch
error:badarith ->
badargs
end.
If your concerned about values of other types being passed in, a better solution would be to add some guards to the function instead:
add(X,Y) when is_number(X), is_number(Y) ->
X + Y.
This ensures that if the function body (X + Y) is only evaluated with numbers. If something other than a number is passed as either of these arguments the process will crash with a "no function clause matching" error. This is the Erlang way of ensuring the types are correct. While Erlang is dynamically typed, but you should generally know ahead of time if the values you have are suitable for the operation you are about to perform. That said, there are times you might not know the types if the variables you have, and in such cases wrapping the call in a case statement handles incorrect types:
case {X, Y} ->
{X, Y} when is_number(X), is_number(Y) ->
% safe to call add/2
add(X, Y);
_ ->
% values aren't both numbers, so we can't add them
nocanadd
end
The second function in your question myfunction/2 really should use guards too. Like this:
myfunction(X,Y) when is_number(X), is_number(Y) ->
case X == Y of
true -> X + Y;
false -> X * Y
end.

How to get an random integer with limit length?

I want to create a function get_id(max_length). At first want to math:pow/2, but it return float data type. It seems not a good idea.
with code as follows, but only support max length=20, as it is hardcoded, any good idea?
seed()->
{M_a,M_b,M_c} = now(),
random:seed(M_a,M_b,M_c),
ok.
get_id(1)-> random:uniform(1);
get_id(2) -> random:uniform(10);
get_id(3) -> random:uniform(100);
get_id(4) -> random:uniform(1000);
get_id(5) -> random:uniform(10000);
get_id(6) -> random:uniform(100000);
get_id(7) -> random:uniform(1000000);
get_id(8) -> random:uniform(10000000);
get_id(9) -> random:uniform(100000000);
get_id(10) -> random:uniform(1000000000);
get_id(11) -> random:uniform(10000000000);
get_id(12) -> random:uniform(100000000000);
get_id(13) -> random:uniform(1000000000000);
get_id(14) -> random:uniform(10000000000000);
get_id(15) -> random:uniform(100000000000000);
get_id(16) -> random:uniform(1000000000000000);
get_id(17) -> random:uniform(10000000000000000);
get_id(18) -> random:uniform(100000000000000000);
get_id(19) -> random:uniform(1000000000000000000);
get_id(20) -> random:uniform(10000000000000000000).
Your approach, unfortunately, doesn't work. Indeed, while random:uniform/1 accepts any positive integer as its argument, it does not deliver a random integer uniformly distributed between 1 and N for very large values of N (in spite of what documentation claims).
The reason is that random:uniform/1 is actually truncating the product of its argument by the value of random:uniform/0 (and adding 1 for [1-N] range instead of [0-(N-1)]).
See source code: https://github.com/erlang/otp/blob/maint/lib/stdlib/src/random.erl#L112
And floats are IEEE 754 doubles with 53 bits mantissa, which means that get_id/1 will not return all possible values for input from 17 to 20 (with 16 or more digits).
random:uniform/0,1 is known as a poor random generator, mostly suitable if you want to generate reproductible pseudo-random series (a given seed value will always generate the same series). For this reason, I would suggest using crypto:rand_uniform/2.
A simple solution would be to compute 10^(N-1) using integer arithmetics (to avoid the 53 bits mantissa issue) and then call crypto:rand_uniform/2. You can perform this with a naive recursive implementation (pow1/1 below), or use binary exponentiation (pow2/1 below).
-define(BASE, 10).
-spec pow1(non_neg_integer()) -> pos_integer().
pow1(N) when N >= 0 ->
pow1(N, 1).
pow1(0, Acc) -> Acc;
pow1(N, Acc) ->
pow1(N - 1, Acc * ?BASE).
-spec pow2(non_neg_integer()) -> pos_integer().
pow2(N) when N >= 0 ->
pow2(?BASE, N, 1).
pow2(_X, 0, Acc) ->
Acc;
pow2(X, N, Acc) when N rem 2 =:= 0 ->
pow2(X * X, N div 2, Acc);
pow2(X, N, Acc) ->
pow2(X * X, N div 2, Acc * X).
Your function could simply be written as:
-spec get_id2(pos_integer()) -> non_neg_integer().
get_id2(N) ->
1 + crypto:rand_uniform(0, pow2(N - 1)).
Alternatively, you could use a combination of uniform random variables, one per digit (while the sum of two random uniform variables is generally not a uniform random variable, it is if combined like this) or for several digits in the case of the binary exponentiation.
With the naive exponentiation:
-spec get_id3(pos_integer()) -> pos_integer().
get_id3(N) when N > 0 ->
get_id3(N - 1, 0).
get_id3(0, Acc) -> 1 + Acc;
get_id3(N, Acc) ->
Acc1 = crypto:rand_uniform(0, ?BASE) + (Acc * ?BASE),
get_id3(N - 1, Acc1).
With the binary exponentiation:
-spec get_id4(pos_integer()) -> pos_integer().
get_id4(N) when N > 0 ->
get_id4(?BASE, N - 1, 0).
get_id4(_X, 0, Acc) ->
1 + Acc;
get_id4(X, N, Acc) when N rem 2 =:= 0 ->
get_id4(X * X, N div 2, Acc);
get_id4(X, N, Acc) ->
Acc1 = crypto:rand_uniform(0, X) + (Acc * X),
get_id4(X * X, N div 2, Acc1).
Why not use trunc/1 to cast the floats returned by math:pow/2 to integers? http://www.erlang.org/doc/man/erlang.html#trunc-1
like in any language, you can get a power of 2 by shifting left the number 1:
1> 1 bsl 3.
8
2> 1 bsl 8.
256
3> 1 bsl 852.
30030067315218800919884630782037027445247038374198014146711597563050526250476926831789640794321325523394216076738821850476730762665208973047045843626559620640158907690363610309346513399556581649279919071671610504617321356178738468477058455548958390664298496
4>
As you can see, the size of integer is not limited in erlang. It is both good and bad since small integer (that is integer represented as a single worg like in most languages) are limited depending on the architecture:
On 32-bit architectures: -134217729 < i < 134217728 (28 bits)
On 64-bit architectures: -576460752303423489 < i < 576460752303423488 (60 bits)
for bigger integer, another representation is used: big integer, that takes more space in memory and take longer to compute.

Easy way to break foldl

I need to break from foldl. Here is a dummy example how to break from fold when I count sum of values in a list and meet too big value (i.e. 10)
L = [1,2,3,4,10,5,6,7],
Res =
try
lists:foldl(
fun(I, Value) ->
if (I < 10) ->
Value + I;
true ->
throw({too_big_value, Value})
end
end,
0, L)
catch
throw:{too_big_value, Value} -> Value
end,
Res.
I know this example is artificial but are there any nice method to break out fold (I know that fold always scan the whole structure)?
Please note, that i need to retrieve correct data even if i break from fold. In this case i should get data from previous iteration (as it done in my example).
Just curious, what is the point of using foldl here? If you need to break out, use recursion, foldl is not designed for it.
main([]) ->
L = [1,2,3,4,5,10,6,7],
io:format("[~w]", [s(L, 0)]).
s([], S) ->
S;
s([H|T], S) ->
if (H < 10) ->
s(T, S + H);
true ->
S
end.
Update:
Another options is to use takewhile:
lists:foldl(fun(E, A) -> A + E end, 0, lists:takewhile(fun(E) -> E < 10 end, L))
You're doing it right, using a throw with try/catch for nonlocal return. If the function looked at the return value from the fun to decide whether or not to continue, it wouldn't be foldl anymore.

Resources