
Infinite work is less work - lizmat
http://blogs.perl.org/users/damian_conway/2019/07/infinite-work-is-less-work.html
======
bigiain
I'm not sure I've wielded Perl in anger in a decade, but I still drop what I'm
doing whenever Damain writes a new post about it... His writing and writing
style and his sense of humour which he intersperses into his techincal mastery
of Perl is still wonderful to read. Even though I reach for Python by default
these days...

~~~
wiremine
I have the pleasure of seeing him and Larry present _years_ ago on Perl 6's
evolution. Their styles were polar opposites, but the comradery was fun to
watch.

I often wonder where we'd be today if Perl 6 had got "finished" 10 years
before it did...

~~~
cutler
Probably with more than a handful of Perl job opportunities nationwide.

------
zachrose
I believe the fancy math word for this “building up” of a value from a
“smaller” initial condition is “anamorphism.”

Most interview-style programming problems are catamorphisms, or “boiling down”
an initial condition to “smaller” result. (For example, summing the numbers in
a string.)

In, say, JavaScript, knowing that you’re implementing a catamorphism usually
(or always?) means that you can convert your input to an array and use the
aptly-named reduce method to write a reducer that works on one piece at a time
to build your result. (Sometimes your reducer needs a sophisticated memo
object to keep track of details, like whether you’re in the middle of multiple
digits.)

If you know you’ll be dealing with an anamorphism in JavaScript, your two
options are a while loop (for an imperative flavor) or a generator (for a
functional flavor).

~~~
lmm
Catamorphisms are more general than reducing an array, e.g. evaluating down a
tree structure (or any other recursive datastructure) is also a catamorphism.

~~~
zachrose
True, but isn’t it also true that a catamorphism on any other data structure
still operates one piece at a time? If so, I think this would imply that you
_could_ concert your tree or whatever to an array and still get your result
with Array#reduce. (Not saying you should, just speculating that it might be
always possible.)

~~~
lmm
> True, but isn’t it also true that a catamorphism on any other data structure
> still operates one piece at a time? If so, I think this would imply that you
> _could_ concert your tree or whatever to an array and still get your result
> with Array#reduce.

No, the catamorphism operates on one part of the structure but that part of
the structure is not necessarily (head, tail) like it is for reduce - rather
it's the "base" shape of the recursive data structure.

E.g. it's easy to write a catamorphism on a tree that finds the maximum number
of children any one node has. But if you flatten the tree into an array then
it's obviously impossible to recover that information.

------
mattashii
> There are an infinite number of primes and of weak primes (and possibly of
> strong primes too, though that's still only conjectured)

Given that a strong prime is < (p[n-1] + p[n+1])/2, and that an infinite
number of prime pairs with prime gap < 400 exist (twin prime conjecture and
derivatives), and that the average prime gap is ln(p[n]), does it then not
also follow that there is an infinite number of strong primes?

~~~
OscarCunningham
Yes, nice! Here's a more rigorous way of proving it:

A strong prime is precisely one for which the prime gap preceding it is
strictly larger than the one following it. There are arbitrarily large prime
gaps (for example none of the n numbers following n! are prime, since n!+m
divides by m whenever m≤n). But it has recently been proven that there are
infinitely many prime gaps with length less than or equal to 246. So given any
strong prime we can find a prime gap after it which is longer than 246, and
then a prime gap after that whose length is less than or equal to 246.
Somewhere in between those two prime gaps there must be a prime at which the
gap size decreases; a strong prime larger than our original strong prime.
Hence there are infinitely many strong primes.

~~~
daveFNbuck
n!+1 can be prime, as primes can be divisible by 1. None of the n-1 numbers
after n!+1 are prime.

~~~
OscarCunningham
Good point! But n-1 still gets arbitrarily large so the proof still works.

------
moomin

        strong :: (Integral i) => [i] -> [i]
        strong = mapMaybe fst3 . scanr g (Nothing, 0, 0)
            where fst3 (x, _, _) = x
                  g n (_, p, pp) = (p <$ guard (2 * p > pp + n), n, p)
    

Haskell makes a better Perl (especially if, like here, you don't bother with
readability).

~~~
oarabbus_
Wow, Haskell is just as opaque as ever to me. I wonder if I'll ever be able to
comprehend this language.

~~~
andolanra
For what it's worth, I've worked as a professional Haskell programmer at
multiple companies and have been writing Haskell for more than a decade, and I
_still_ have trouble reading code written in that style. I usually end up
decomposing it at a REPL so I can look at the types of intermediate parts of
the program.

(In practice, most—although not all, admittedly—of the Haskell codebases I've
worked with tended to be a lot less dense than the occasional combinator-heavy
sample code you see in blog posts and comments.)

------
xisukar
I've gone through most of the comments and it seems that some commenters are
either

* referring to Perl 6 as Perl, or

* mistaking Perl 6 for Perl 5.

Although from the same family of programming languages, Perl (or Perl 5) and
Perl 6 (or Raku[1]) are two completely different languages.

The article is about Perl 6 (or Raku), not Perl 5.

[1]
[https://docs.perl6.org/language/faq#What's_the_difference_be...](https://docs.perl6.org/language/faq#What's_the_difference_between_Raku,_Rakudo_and_Perl_6)?

~~~
yakovdk
I think this "different language" concept is in many ways either revisionist
history or scope creep. Originally, Larry said he wanted to remove historical
warts, clean up the language design, and etc. I think the apocalyptic and
exegetical snowball rolled faster than expected, and after the mushroom cloud
dissipated and the dust cleared it was easier to say, "Oh, it's a completely
different language."

~~~
xisukar
As Grinnz notes, I also think it's both:

\- revisionist history. For most intent and purposes, Perl 5 and Perl 6 are
two different languages and pretending otherwise helps nobody. In fact, it
just creates misunderstandings and misplaced expectations. But why didn't they
change the language's name a lot sooner? I honestly don't know. If many of the
people involved in the project would've acted sooner, things such as
clarifying that Perl 5 and Perl 6 are actively-developed, independent and
different languages, even when the names suggest otherwise, would be things of
the past. Nonetheless, even now there's the alias Raku, the name Perl 6 is the
most used and probably will be for time to come. Will it catch on?

\- scope creeps. As you state, Wall's goal was "to remove historical warts,
clean up the language design, etc" which he deemed "the community's rewrite of
Perl and of the community." but as we all know, things changed along the way
(e.g., untimely delivery) and Perl 6 turned out to be a total different
language to Perl 5 or to what many people envisioned as the replacement for
Perl 5.

------
saagarjha
Lazy, functional, and pretty: I had no idea Perl could be this nice!
(Actually, I know next to zero Perl, but that's not the point…)

~~~
collyw
Perl gets a bad rep, but a decent programmer should be able to write readable
Perl.

~~~
majewsky
> readable Perl

I worked with Perl 5 intensively for three years and know the language in and
out. These Perl 6 snippets there are mostly foreign to me. It's like how a
non-Perler looks at Perl 5: mostly a mess of unexpected symbols with some
recognizable keywords inbetween.

~~~
mhd
It's a bit like if a C programmer looks at a Schwartzian transform.

------
vincent-toups
That people still use this wacky ass language is a kind of charming miracle.

~~~
donaldihunter
Care to elaborate what is 'wacky ass' in Perl 6?

~~~
yellowapple
Perl 6 is pretty "wacky ass" throughout. The crazy blending of object
orientation and functional programming, the twigils, the built-in support for
PEGs, the scoping rules, the operators, lots of things.

I like it, though. Perl 6 is a fun language in which to program, and it's
therefore one I like trying to use, even if said use is less than practical.

------
anandology
I think Infinity can be handled lot more elegantly in Python.

Here is my response with the same problem solved in Python.

[https://anandology.com/blog/python-is-infintely-
beautiful/](https://anandology.com/blog/python-is-infintely-beautiful/)

~~~
roberto
You can replace your `integers` function with `itertools.count` (same
signature but defaults to starting at 0), and `take` with `itertools.islice`.

~~~
anandology
Didn't realize I could use `itertools.count`. In fact, it accepts a `start`
parameter.

The `take` function is borrowed from Haskell. It feels lot more natural to
say/read `take(10, primes())`, than `islice(primes(), 10)`.

------
mikepurvis
> However, as we stopped generating primes at 100, the &strong subroutine
> would have received an undefined value when it requested that n+1th prime.
> _When used as a number, that undefined value would convert to zero_ , so the
> average of 97's two prime neighbours would be computed as (89+0)/2

I think I prefer Python's behaviour here, of just raising an OutOfRangeError,
and not permitting NoneType to be coerced as an number.

~~~
donaldihunter
Well Damian's program actually reports "Use of uninitialized value of type Any
in numeric context" which the programmer can choose to be a warning or an
exception.

------
evandijk70
I am not familiar with Perl 6, nor with list comprehensions, but I am
wondering if this is really more readable than the 'traditional' way of
looping through the prime numbers and appending to the list, like this:

    
    
      strongs=[]
      weaks=[]
    
      n=1
      AskedNumbers=10
      while len(strongs) < AskedNumbers:
        if p(n) * 2 > ( p(n-1) + p(n+1) ):
           if len(strongs) < AskedNumbers:
             strongs.append(p(n))
        if p(n) * 2 < ( p(n-1) + p(n+1)):
           if len(weaks) < AskedNumbers:
             weaks.append(p(n))
        n+=1
      print(strongs)
      print(weaks)

~~~
eequah9L
I am not familiar with Perl at all, though I am with list comprehensions, and
FWIW I find the code very readable. (Though the lambda syntax was not obvious
at first.)

What I would worry about is performance. But we are talking about top ten
numbers, so whatever. (If it does actually matter, just precompute the lists.)
But for larger sets I would check how is-prime is actually implemented :)

[EDIT: Grammar.]

------
markstos
I was a Perl 5 developer for over a decade and didn't recognize this as valid
Perl.

~~~
chaosfox
this is not valid Perl, its Perl 6.

~~~
markstos
I understood it was about Perl 6, but I thought the article was starting off
with some pseudo-code or some other language.

------
lenkite
So variables in Perl 6 can be _sigil-less_...by prefixing a backslash like my
\p = [];

Umm.. backslash _is_ a sigil. Why do we need to add this ?

~~~
yellowapple
You only need the sigil during definition. So, for example (in the Perl 6
REPL):

    
    
        > my \x = 1
        1
        > my \y = 2
        2
        > say "Look Ma, no punctuation!" if x + y == 3
        Look Ma, no punctuation!
    

There are some implications of this; namely: x and y are now immutable. Back
in the REPL:

    
    
        > my \x = 1
        1
        > x = 2
        Cannot modify an immutable Int (1)
          in block <unit> at <unknown file> line 1
    

This is because in Perl6 the sigil is a _container_ for the value represented
by that variable, so since you don't have a sigil, you don't have a container;
that is: the names "x" and "y" are now literal synonyms for "1" and "2"
(respectively). "x = 2" fails here for the same exact reason (and with the
same exact error message) you'd get if you tried to do "1 = 2".

~~~
xisukar
Sweet explanation ;-)!

For those interested on learning more about containers in Raku, lizmat wrote a
nice article about them [1]. There's also this documentation page [2] that
gives a detailed overview of them, where you can find more about sigilless
variables.

[1] [https://opensource.com/article/18/8/containers-
perl-6](https://opensource.com/article/18/8/containers-perl-6)

[2]
[https://docs.perl6.org/language/containers](https://docs.perl6.org/language/containers)

------
gowld
Using "infinite" when you mean "lazily generated" is a large source of
confusion for learners of math, computer science, and programming.

Infinite things don't exist in computing, and infinite things in math are not
the same as lazily-generated things. Conflating terminology makes the truth
harder to understand. People prove statements about infinite objects and then
misapply them to lazily-generated objects.

~~~
markstos
The infinity symbol is part of the code. This is about "the first N elements
of an infinite sequence".

Explaining laziness without infinite lists makes laziness harder to
understand.

