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.