print [(x,x+2) for x in primes if (x+2 in primes)]
print [(x,y) for x, y in zip(primes, primes[1:]) if x+2 == y]
The simpler one doesn't even require the primes list to be sorted, so I thought the second one would be more equivalent. It's still a lot easier to read and write than Egison one. my @primes = (1..∞).grep: *.is-prime;
my @twin_primes = map { ($_, $_+2) }, @primes.grep: (*+2).is-prime;infinite symbol gives away 6
So, yeah. Correct me if I'm wrong.
A slightly less listy pattern style is to declare types. Like I'd prefer this sort of declarative style:
subset Prime of Int where *.is-prime;
subset TwinPrime of Prime where (* + (2|-2)).is-prime;
my @twin_primes = grep TwinPrime, ^Inf;
Just feels a lot more clear what my intent is and I get some cheap types for later, to use in function parameters that require twin primes.How is performance on a task like this compared to, say, Python?
Pattern-matching would be even more obvious is a piece of Haskell:
pair :: [x] -> Maybe (x, x)
pair p:q:rest = if q = p + 2 then Just (p, q) else Nothing
pair _ = Nothing
findTwins primes = [x | x <- map pair primes]
I suppose that Eigson's power lies in matching of more complex structures, as they mention non-linear matching, matching with multiple results, matching with lexical scoping. import Data.List
primes = Data.List.nubBy (\a b -> gcd a b > 1) [2..]
findTwins primes = [(p,q) | (p:q:_) <- tails primes, q == p+2]
main = mapM_ print . take 10 . findTwins $ primes
Finding primes arbitrarily far apart can be done in Haskell as findBigTwins gap primes = [(p,q) | (p:qs) <- tails primes, let q = p+gap, q `elem` takeWhile (<= q) qs]The power of Egison's pattern matching becomes more obvious when we consider more general pattern such as (p, p+ 100) not only (p, p+2).
We can write the first 5 prime pairs whose form is (p, p+100) with a small modification for pattern matching for twin primes.
(take 5
(match-all primes (list integer)
[<join _ <cons $p <join _ <cons ,(+ p 100) _>>>>
[p (+ p 100)]]))
;=>{[3 103] [7 107] [13 113] [31 131] [37 137]}Not only that, but you have redundancy between the ,(+ p n) part of the pattern and the emitted result of [p (+ p n)].
Point being: I applaud the attempt here, but it's not something I'll ever want to use.
So what it does is matching of such elements (named p) that the next element (see cons) equals p+2, which would be a twin prime, since p is a prime. Then it generates an element consisting of a pair [p, p+2]. The pattern apparently matches such a list comprised of elements (see <join ... >) that are [p, p+2] (the inner <cons ...>).
You definitely remember that Lisp lists are singly-linked lists, and (cons head tail) prepends a new head element to the list tail. This is why it is matched, pertty similarly to how it's done in Haskell.