packages feed

mini-egison-0.1.0: test/Spec.hs

{-# LANGUAGE GADTs       #-}
{-# LANGUAGE QuasiQuotes #-}

module Spec (spec) where

import           Control.Egison
import           Data.Numbers.Primes
import           Test.Hspec

--
-- Basic list processing functions in pattern-matching-oriented programming style
--

pmap :: (a -> b) -> [a] -> [b]
pmap f xs = matchAll xs (List Something)
             [[mc| join _ (cons $x _) => f x |]]

pmConcat :: [[a]] -> [a]
pmConcat xss = matchAll xss (Multiset (Multiset Something))
                 [[mc| cons (cons $x _) _ => x |]]

spec :: Spec
spec = do
  describe "list and multiset matchers" $ do
    it "cons pattern for list" $
      matchAll [1,2,3] (List Integer) [[mc| cons $x $xs => (x, xs) |]]
      `shouldBe` [(1, [2,3])]

    it "multiset cons pattern" $
      matchAll [1,2,3] (Multiset Integer) [[mc| cons $x $xs => (x, xs) |]]
      `shouldBe` [(1,[2,3]),(2,[1,3]),(3,[1,2])]

    it "join pattern for list matcher" $ length (
      matchAll [1..5] (List Integer)
        [[mc| join $xs $ys => (xs, ys) |]])
      `shouldBe` 6

    it "value pattern for list matcher (1)" $
      match [1,2,3] (List Integer)
        [[mc| #[1,2,3] => "Matched" |],
         [mc| _ => "Not matched" |]]
      `shouldBe` "Matched"

    it "value pattern for list matcher (2)" $
      match [1,2,3] (List Integer)
        [[mc| #[2,1,3] => "Matched" |],
         [mc| _ => "Not matched" |]]
      `shouldBe` "Not matched"

    it "value pattern for multiset matcher" $
      match [1,2,3] (Multiset Integer)
        [[mc| #[2,1,3] => "Matched" |],
         [mc| _ => "Not matched" |]]
      `shouldBe` "Matched"

  describe "match-all with infinitely many results" $ do
    it "Check the order of pattern-matching results" $
      take 10 (matchAll [1..] (Multiset Integer)
                 [[mc| cons $x (cons $y _) => (x, y) |]])
      `shouldBe` [(1,2),(1,3),(2,1),(1,4),(2,3),(3,1),(1,5),(2,4),(3,2),(4,1)]

  describe "built-in pattern constructs" $ do
    it "Predicate patterns" $
      matchAll [1..10] (Multiset Integer)
        [[mc| cons (& (PredicatePat (\x -> mod x 2 == 0)) $x) _ => x |]]
      `shouldBe` [2,4,6,8,10]

  describe "patterns for prime numbers" $ do
    it "twin primes (p, p+2)" $
      take 10 (matchAll primes (List Integer)
                 [[mc| join _ (cons $p (cons #(p+2) _)) => (p, p+2) |]])
      `shouldBe` [(3,5),(5,7),(11,13),(17,19),(29,31),(41,43),(59,61),(71,73),(101,103),(107,109)]

    it "prime pairs whose form is (p, p+6) -- pattern matching with infinitely many results" $
      take 10 (matchAll primes (List Integer)
                 [[mc| join _ (cons $p (join _ (cons #(p+6) _))) => (p, p+6) |]])
      `shouldBe` [(5,11),(7,13),(11,17),(13,19),(17,23),(23,29),(31,37),(37,43),(41,47),(47,53)]

    it "prime triplets -- and-patterns, or-patterns, and not-patterns" $
      take 10 (matchAll primes (List Integer)
                 [[mc| join _ (cons $p (cons (& (| #(p+2) #(p+4)) $m) (cons #(p+6) _))) => (p, m, p+6) |]])
      `shouldBe` [(5,7,11),(7,11,13),(11,13,17),(13,17,19),(17,19,23),(37,41,43),(41,43,47),(67,71,73),(97,101,103),(101,103,107)]

  describe "Basic list processing functions" $ do
    it "map" $
      pmap (+ 10) [1,2,3] `shouldBe` [11, 12, 13]
    it "concat" $
      pmConcat [[1,2], [3], [4, 5]] `shouldBe` [1..5]
    -- it "uniq" $
    --   pmUniq [1,1,2,3,2] `shouldBe` [1,2,3]