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

Jesper Louis Andersen <>
Wed Sep 2 15:23:03 CEST 2015


On Wed, Sep 2, 2015 at 4:24 AM, Lloyd R. Prentice <>
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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20150902/3edd20fe/attachment.html>


More information about the erlang-questions mailing list