[erlang-questions] Tried this... Thought it interesting... But it didn't work.

lloyd@REDACTED lloyd@REDACTED
Wed Sep 2 22:21:18 CEST 2015


Hi Jesper,

When are you going to write your Erlang book? You have much to teach and I, for one, much appreciate it.

All the best,

Lloyd

-----Original Message-----
From: "Jesper Louis Andersen" <jesper.louis.andersen@REDACTED>
Sent: Wednesday, September 2, 2015 9:23am
To: "Lloyd R. Prentice" <lloyd@REDACTED>
Cc: "zxq9" <zxq9@REDACTED>, "Erlang (E-mail)" <erlang-questions@REDACTED>
Subject: Re: [erlang-questions] Tried this... Thought it interesting... But it didn't work.

On Wed, Sep 2, 2015 at 4:24 AM, Lloyd R. Prentice <lloyd@REDACTED>
wrote:

> Your code exhibits a depth of understanding and subtlety that I can only
> hope to aspire to.
>
> Can you help me understand the ?LET(... and ?SUCHTHAT(... expressions?
>

I agree with Fernando, that it is often nicer to pull these things into a
function on its own, and use that function as in:

f(X) -> [1,2] ++ e(X).
e(X) when X < 5 -> [];
e(X) -> [X].

In the QuickCheck models however, you would often end up writing many of
such one-off functions, so this is why I sometimes tend to use the [X ||
test()] scheme.

As for ?LET(...) and ?SUCHTHAT(...): They are macros which are used in
QuickCheck like tools (Erlang QuickCheck, Proper, Triq, ...). If you have a
generator like choose/2 which generates numbers between two endpoints:

6> triq_dom:sample(
        triq_dom:choose(1, 10)).
[5,9,1,3,7,6,1,5,3,8,9]

Some times, however, you don't want a raw generator. You want to do
something to the result before you use it. The problem however is that the
generator generates. So your code would have to:

1. draw a specimen from the generator.
2. apply some function to the drawn specimen
3. return the result of the application, but do so as a new generator doing
this!

This is what ?LET(...) does[0]. Writing

?LET(I, choose(1,10),
    I * 7).

would return a new generator, which draws a number between 1 and 10, and
returns 7 times that number. That is, it returns numbers in the range
[7,14,21,28,...,70].

The ?SUCHTHAT(..) macro is used as ?SUCHTHAT(S, Gen, Pred(S)). It picks a
specimen from Gen and then tests it against Pred. If Pred(S) returns true,
it returns that value. If Pred(S) returns false, it tries generating a new
value satisfying the predicate. I.e., generate S from Gen such that P(S) is
true. ?SUCHTHAT(..) itself is a generator, doing this internally[1].

You use the ?SUCHTHAT(..) macro to reject certain values which are not
desirable. In the case of trying to remove an element from a map, you want
to generate an element that is not present in the map in some cases. This
is to verify such removal has no effect on the map. So I use a
?SUCHTHAT(...) to make sure the generated target is not already present in
the map. I expect to be able to find such a value in relatively few tries.
Even considering very large maps with thousands of elements, you can easily
generate a new element randomly, which isn't in there.


[0] ?LET(..) is a monadic bind over the quickcheck monad.

[1] The caveat of ?SUCHTHAT is that you want it to generate a valid value
fairly quickly. If you are drawing random hay from a haystack to find a
needle, and the haystack is large, then it is a bad idea. You have a random
search problem at hand then.


-- 
J.





More information about the erlang-questions mailing list