Related
I'm new in the Erlang world. I'm trying to implement the function split_binary. The function takes as input (list, index) and it splits the list in two lists according to the index.
split(Lst, N) when N>=list:lenght(Lst) -> Lst;
split(Lst, N) when N<list:lenght(Lst) -> splitHelper(list:reverse(Lst), 0, N, []).
splitHelper([H|T], X, N, Acc) ->
if
X>=N ->
(list:reverse([H|T]), list:reverse(Acc));
X<N ->
splitHelper(T, X+1, N, [H|Acc])
end.
How can I improve my code?
I'm new in the Erlang world. I'm trying to implement the function
split_binary. The function takes as input (list, index) and it splits
the list in two lists according to the index.
According to the erlang docs for split_binary/2, the two arguments are a binary, which is not a list, and the number of bytes where you want to split the binary.
First, you need to have a basic understanding of what a binary is. A binary is a sequence of bytes, where each byte is 8 bits representing some integer, e.g.
0010 0001
which is 33. Here is an example of a binary:
<<1, 2, 3>>
When you don't specify a size for each integer, by default each integer will occupy one byte. If you wanted the 2 to occupy two bytes instead, i.e. 0000 0000 0000 0010, which is 16 bits, then you could write:
<<1, 2:16, 3>>
which the shell would display as:
<<1,0,2,3>>
Huh? Where did that 0 come from? The shell displays a binary byte by byte, and the first byte of the integer 0000 0000 0000 0010 is 0000 0000, which is 0.
Next, you can step through a binary just like you can for a list, extracting any number of bits at a time from the front of the binary. It so happens that split_binary/2 extracts 8 bits, or 1 byte, at a time from the head of the binary.
There are a couple of tricks to learning how to step through a binary:
For lists, [] means an empty list, and for binaries <<>> means an empty binary.
For lists you write [Head|Tail] to extract the head of the list, and for binaries you write <<Bits:3, Rest/binary>> to extract 3 bits from the front of the binary. In your case, you need to extract 8 bits from the front of the binary.
Here is an example of what you can do:
-module(a).
-compile(export_all).
split_b(Bin, N) ->
split_b(Bin, N, _Acc = <<>>).
split_b( Bin, _N = 0, Acc) -> [Acc, Bin];
split_b(<<Bits:8, Rest/binary>>, N, Acc) ->
split_b(Rest, N-1, <<Acc/binary, Bits>>).
In the shell:
40> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
41> a:split_b(<<5,6,7>>, 1).
[<<5>>,<<6,7>>]
42> a:split_b(<<5,6,7>>, 2).
[<<5,6>>,<<7>>]
Note that when constructing a binary one of the segments of the binary can be another binary:
23> Bin = <<1, 2, 3>>.
<<1,2,3>>
24> Acc = <<Bin/binary, 4>>.
<<1,2,3,4>>
If you are actually trying to implement lists:split/2, you can do this:
-module(a).
-compile(export_all).
split_l(N, List) ->
split_l(N, List, _Acc=[]).
split_l(_N=0, List, Acc) ->
[lists:reverse(Acc), List];
split_l(N, [H|T], Acc) ->
split_l(N-1, T, [H|Acc]).
In the shell:
2> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
3> a:split_l(1, [10, 20, 30]).
["\n",[20,30]]
4> shell:strings(false).
true
5> a:split_l(1, [10, 20, 30]).
[[10],[20,30]]
6> a:split_l(2, [10, 20, 30]).
[[10,20],[30]]
I think #7stud's answer is the best one, but I wanted to add a few minor details about your code, without actually checking if it works or not…
list:lenght/1 doesn't exist (unless you also created your own list module.
If you created your own list module, you can't use it in guards. Only BIFs are allowed there.
If you're trying to use stdlib's function to check the length of a list, then you should use erlang:length/1 or just length/1.
It's more idiomatic in Erlang to use snake_case (e.g. split_helper) instead of camelCase (e.g. splitHelper) for module names, function names and atoms in general.
You can use pattern-matching directly instead of writing an if as the sole expression of your function…
split_helper([H|T], X, N, Acc) when X > N ->
(list:reverse([H|T]), list:reverse(Acc));
split_helper([H|T], X, N, Acc) when X<N ->
split_helper(T, X+1, N, [H|Acc]).
Tuples are denoted with curly braces and not parentheses: {list:reverse([H|T]),…. BTW… This should have prevented your code from compiling at all. The error should've looked like syntax error before: ','
Also, you might have written your own list module, but if not and if you're trying to use stdlib functionality, it's lists:reverse/1 not list:reverse/1.
Finally, out of that list, I would strongly recommend you to write some simple tests for your code. This article may help you with that.
How to perform arithmetic with values of different widths ?
In verilog there is no problem xoring 2 bits with 8 bits but cryptol complains:
cryptol> let test(x: [2],y: [8]) = x ^ y
[error] at <interactive>:1:31--1:32:
Type mismatch:
Expected type: 2
Inferred type: 8
My original problem:
I would like to rotate the bytes in a 64 bit value, with the number of bytes to shift depending on a two bit input. I struggle to get this working:
cryptol> let shift (v, s:[2]) = v >>> (s*16+8)
[error] at <interactive>:1:5--1:38:
Unsolved constraint:
2 >= 5
arising from
use of literal or demoted expression
at <interactive>:1:33--1:35
In the interpreter I can remove the type specification of s and then it works however I need to get that working from a file and with s being really a 2 bit value.
The type of ^ is:
Cryptol> :t (^)
(^) : {a} (Logic a) => a -> a -> a
Note that it requires both arguments to be exactly the same. You're getting the type-error because [2] is not the same as [8]; as they differ in size. Unlike Verilog, Cryptol will not "pad" things implicitly, and I think Cryptol is definitely doing the right thing here. Verilog programmers can chime in with countless bugs they had due to implicit casting.
All such casting in Cryptol has to be explicit.
The typical way to deal with this situation in Cryptol is to use the polymorphic constant zero:
Cryptol> :t zero
zero : {a} (Zero a) => a
The value zero inhabits all types (you can ignore the Zero constraint for now), and as you can imagine is the "right" padding value in this case. So, you'd define your function as:
Cryptol> let test(x:[2], y:[8]) = (zero#x)^y
Cryptol> :t test
test : ([2], [8]) -> [8]
And use it like this:
Cryptol> test (1, 5)
0x04
And if you wanted to pad on the right for some reason, you'd do:
Cryptol> let test(x:[2], y:[8]) = (x#zero)^y
Cryptol> test(1,5)
0x45
This way, everything is explicit and you don't have to know all the magical rules about how things get padded to become the right size.
If you want to get real fancy, then you can do:
Cryptol> let test(x, y) = (zero#x)^(zero#y)
Cryptol> :t test
test : {n, m, i, j, a} (Logic a, Zero a, m + i == n + j, fin n,
fin m) =>
([i]a, [j]a) -> [m + i]a
Now, that type looks a bit scary; but essentially it's telling you that you can give it any sized arguments, and it would be valid for any other size, so long as the new size is larger than the maximum of the two you've given. Of course, this inferred size is way more polymorphic then you probably cared for; so you can give it something more readable:
test : {m, n} (fin m, fin n) => [m] -> [n] -> [max m n]
test x y = (zero#x) ^ (zero#y)
I believe this captures your intent perfectly. Note how cryptol will make sure your inputs are finite, and you get the maximum of the two sizes given.
Getting back to your example, Cryptol is telling you that to multiply by 16 you need at least 5 bits, and thus 2>=5 is not satisfiable. This is a bit cryptic, but arises from the use of literals which are polymorphically typed. You can use the zero trick to address the issue in the same way as before:
Cryptol> let shift (v, s:[2]) = v >>> ((zero#s)*16+8)
[warning] at <interactive>:1:32--1:38:
Defaulting type argument 'front' of '(#)' to 3
But note how cryptol is warning you about the type of zero that's used there, since the type of >>> is polymorphic enough to allow different size shifts/rotates:
Cryptol> :t (>>>)
(>>>) : {n, ix, a} (fin n, fin ix) => [n]a -> [ix] -> [n]a
In these cases, Cryptol will pick the smallest possible size to default to by looking at the expressions. Unfortunately, it does the wrong thing here. By picking size 3 for zero, you'll have a 5 bit shift, but your expression can produce the maximum value of 3*16+8=56, which requires at least 6 bits to represent. Note that Cryptol only uses the minimum size required to handle the multiplication there, and does not care about overflows! This is why it's important to pay attention to such warnings.
To be clear: Cryptol did the right thing per the language rules on how type inference works, but it ended up picking a size that is just too small for what you wanted to do.
So, you should write your shift as follows:
Cryptol> let shift (v, s:[2]) = v >>> (((zero:[4])#s)*16+8)
Cryptol> :t shift
shift : {n, a} (fin n) => ([n]a, [2]) -> [n]a
The important thing here is to make sure the expression s*16+8 will fit in the final result, and since s is only 2 bits wide the largest value will be 56 as discussed above, which needs at least 6-bits to represent. This is why I chose [4] as the size of zero.
The moral of the story here is that you should always be explicit about the sizes of your bitvectors, and Cryptol will give you the right framework to express your constraints in a polymorphic way to allow for code reuse without ambiguity, avoiding many of the pitfalls of Verilog and other similar languages.
I was reading Learn You Some Erlang and I came upon this example in the Recursion chapter.
tail_sublist(_, 0, SubList) -> SubList;
tail_sublist([], _, SubList) -> SubList;
tail_sublist([H|T], N, SubList) when N > 0 ->
tail_sublist(T, N-1, [H|SubList]).
As the author goes on to explain that there is a fatal flaw in our code. It being that the sub lists hence produced would be reverse and we would have to re-reverse them to get the correct output. In contrast, what I did was use the ++ operator to avoid reversing the list later.
sublist_tail([],_,Acc) -> Acc;
sublist_tail(_,0,Acc) -> Acc;
sublist_tail([H|T],N,Acc) -> sublist_tail(T,N-1,Acc++[H]).
My question is, is the ++ operator more expensive than the | operator? And if it is, would my solution (using ++ operator) still be slow compared to the author's solution (including reversing the list to get the correct output)?
You might want to read about this issue in the Erlang efficiency guide, since there it says that building the list via | and then reversing the result is more efficient than using the appending ++ operator. If you want to know the performance difference, use timer:tc:
1> timer:tc(fun() -> lists:reverse(lists:foldl(fun(V, Acc) -> [V|Acc] end, [], lists:seq(1,1000))) end).
{1627,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
2> timer:tc(fun() -> lists:foldl(fun(V, Acc) -> Acc++[V] end, [], lists:seq(1,1000)) end).
{6216,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
Both approaches create lists of 1000 integers, but these measurements based on Erlang/OTP 17.5 show the prepending/reversing version is roughly 4x faster than the appending version (YMMV of course).
is the ++ operator more expensive than the | operator?
That depends. If you use it correctly, then no. ++ is only dangerous when you have a big left-hand-side operand.
Each time a "++"-operator is invoked on a left-hand List (like: List1 ++ List2), you are creating a new List, that is a copy of your left-hand operand (List1). Each copy operation then has a runtime, that is dependent on the length of your List1 (which keeps growing with your iterations).
So, if you prepend your values 'head first', you don't have to perform a copy-operation over the whole list in each step. This also means, accumulation with ++ at the head of the List wouldn't be so bad either, since only the "H"-value is copied once in each iteration:
sublist_tail([H|T],N,Acc) -> sublist_tail(T,N-1,[H]++Acc).
But if you are already accumulating head-first (and thus have to reverse later anyhow), you can do it with the cons-operator (|)
sublist_tail([H|T],N,Acc) -> sublist_tail(T,N-1,[H|Acc]).
This is the 'proper' way, since (please correct me if I am wrong) ++ is only syntactic sugar and is implemented internally with a cons-operator (|).
I'm in the process of learning Elixir and I was curious why the following occurs:
iex(4)> case {:one, :two} do
...(4)> {:four, :five} ->
...(4)> "This won't match"
...(4)> {:one, x} ->
...(4)> "This will match and bind `x` to `:two`"
...(4)> _ ->
...(4)> "This will match any value"
...(4)> end
"This will match and bind `x` to `:two`"
So if in this 'Pattern Matching' example, why does the empty variable x automatically bind to the atom :two and provide a positive match? x doesn't equal :two when this case is first run.
I'm just not grasping what exactly is going on.
Thanks.
Pattern matching in a clause (case or function) performs the same operation as {:one, x} = {:one, :two} (which is also pattern matching). In this second case it is obvious that you want to test if the 2 expressions match, and you want to bind the variable x if it was unbound previously. The only difference is that if the match fails in a clause (for example {:four, :five} = {:one, :two}) , it will try the next clause if any previous clause is throwing an exception.
It is a very powerful feature because it does a lot of operations with very few lines and keeps the code easy to read.
x doesn't equal :two when this case is first run.
Exactly. x is an unbound variable, so it can match against anything (and will then be bound to what it matched). In this case, {:one, x} successfully matches {:one, :two} (since x can match anything), and since x was unbound, it can now be bound to :two.
Is it possible to implement a closure in Erlang?
For example, how would I translate this snippet from Scheme?
(define (make-adder n)
(lamdba (x) (+ x n)))
I've tried the following, but I'm clearly missing something.
make_adder(n) ->
fun (x) -> x + n end.
Compiling this gives the error
Warning: this expression will fail with a 'badarith' exception
You can't add atoms. Variables start with Capital Letters in erlang. words starting with lower case letters are atoms.
In other words your problem is not related to funs at all, you just need to capitalize your variable names.
make_adder(N) ->
fun (X) -> X + N end.
Variables start with Capital Letters in erlang.
words starting with lower case letters are atoms.