[erlang-questions] Sunday puzzle - trying to improve my Erlang

Richard A. O'Keefe <>
Tue Jul 8 03:47:09 CEST 2008

An answer to the puzzle _could_ be something as simple as

	io:format("VIER = 6241, NEUN = 9409\n")

*Some* amount of human judgement will be needed to convert
the problem specification to executable code.  For example,
one way to find candidates is to enumerate integers in a
certain range, square them, and check whether the squares
have a suitable digit pattern.  But what range of integers?
Looking at it, _we_ see that the range need not be any more
than 32..99, but given that, the rest is pretty much
trivial.  (sqrt(VIER) = 79, sqrt(NEUN) = 97, which is quite
pretty.)  You can get a short list for NEUN thus:

neun_candidates() ->
     [{N,E,U,NEUN} ||
	X <- lists:seq(32, 99),
	NEUN <- [X*X],
	[N,E,U,N] <- [integer_to_list(NEUN)],
	N /= E, N /= U, E /= U].
which returns the list
[{$1,$5,$2,1521}, {$1,$6,$8,1681}, {$4,$6,$2,4624},
  {$5,$6,$2,5625}, {$9,$4,$0,9409}].
The code for vier_candidates() is similar.
Pasting them together is just

vier_neun_candidates() ->
    A = vier_candidates(),
    B = neun_candidates(),
    [{VIER,NEUN} ||
        {V,I,E,R,VIER} <- A,
        {N,E,U,  NUEN} <- B,
        % some testing goes here

Then it's simply a matter of checking the last condition

answer() ->
     C <- vier_neun_candidates(),
     [{VIER,NEUN} ||
         {VIER,NEUN} <- C,
         X <- [[OOPS || {VIER,OOPS} <- C, OOPS /= NEUN]],
         X == [],
         Y <- [[JUNK || {JUNK,NEUN} <- C, JUNK /= VIER]],
	Y == []].

Finishing the details left for anyone interested.
One comment I _will_ make is that there is a rather pointless
restriction in Erlang syntax: the generator of a list
comprehension *may* include "X <- [expr]" but may *not*
include "X = expr", which means exactly the same thing.

neun_candidates() ->
     [{N,E,U,NEUN} ||
	X <- lists:seq(32, 99),
	NEUN = X*X,
	[N,E,U,N] = integer_to_list(NEUN),
	N /= E, N /= U, E /= U].

would have been much clearer.

More precisely, Erlang *does* allow these expressions
BUT WITH THE WRONG MEANING!  A qualifier that is
	<pattern> = <expression>
should SUCCEED or FAIL, and if it succeeds, the
value it returns is quite irrelevant and should by NO
means be restricted to 'true' or 'false'.

Another way to hack around this is to rewrite
	Pat = Expr
as	(Pat = Expr, true)
but that has the wrong semantics too, because when
the value of Expr doesn't match Pat, we simply want
that iteration of the list comprehension to fail,
not to produce an exception in the whole thing.

What could break if this part of Erlang syntax were fixed?
Let us suppose that nobody writes list comprehensions
	Nonvar = Expr
because they could and should be rewritten to use == or
=:=.  Would
	_ = Expr
make sense?  No, because it would be equivalent to
	X = Expr
make sense?  No, because it would be equivalent to
	Expr, X = true
and what would be the point of that?

It really is past time that something was done about this.
If the current badly broken semantics cannot be changed,
then at least a compile-time warning for any list
comprehension containing Pat = Expr that it is almost
certainly incorrect would be helpful.

More information about the erlang-questions mailing list