{"id":18571847,"url":"https://github.com/egison/egison-haskell","last_synced_at":"2025-04-10T07:30:48.521Z","repository":{"id":56847056,"uuid":"163386520","full_name":"egison/egison-haskell","owner":"egison","description":"Template Haskell Implementation of Egison Pattern Matching","archived":false,"fork":false,"pushed_at":"2020-07-13T00:37:24.000Z","size":260,"stargazers_count":31,"open_issues_count":3,"forks_count":2,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-04-24T20:26:55.359Z","etag":null,"topics":["backtracking","egison","haskell","non-linear-pattern","pattern-matching"],"latest_commit_sha":null,"homepage":"http://hackage.haskell.org/package/mini-egison","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/egison.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-28T08:29:24.000Z","updated_at":"2023-03-24T12:37:00.000Z","dependencies_parsed_at":"2022-09-12T11:44:13.974Z","dependency_job_id":null,"html_url":"https://github.com/egison/egison-haskell","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egison%2Fegison-haskell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egison%2Fegison-haskell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egison%2Fegison-haskell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egison%2Fegison-haskell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/egison","download_url":"https://codeload.github.com/egison/egison-haskell/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223430338,"owners_count":17143624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backtracking","egison","haskell","non-linear-pattern","pattern-matching"],"created_at":"2024-11-06T23:03:57.931Z","updated_at":"2024-11-06T23:03:58.003Z","avatar_url":"https://github.com/egison.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# miniEgison: Template Haskell Implementation of Egison Pattern Matching\n[![Build Status](https://travis-ci.org/egison/egison-haskell.svg?branch=master)](https://travis-ci.org/egison/egison-haskell)\n\nThis Haskell library provides the users with the pattern-matching facility against non-free data types.\nNon-free data types are data types whose data have no standard forms.\nFor example, multisets are non-free data types because the multiset {a,b,b} has two other equivalent but literally different forms {b,a,b} and {b,b,a}.\nThis library provides the pattern-matching facility that fulfills the following three criteria for practical pattern matching for non-free data types: (i) non-linear pattern matching with backtracking; (ii) extensibility of pattern-matching algorithms; (iii) ad-hoc polymorphism of patterns.\n\nThe design of the pattern-matching facility is originally proposed in [this paper](https://arxiv.org/abs/1808.10603) and implemented in [the Egison programming language](http://github.com/egison/egison/).\n\n## Grammar\n\nThis library provides two syntax constructs, `matchAll`, `match`, `matchAllDFS`, and `matchDFS` for advanced pattern matching for non-free data types.\n\n```\ne ::= hs-expr                    -- arbitrary Haskell expression\n    | matchAll e e [C, ...]      -- match-all expression\n    | match e e [C, ...]         -- match expression\n    | matchAllDFS e e [C, ...]   -- match-all expression\n    | matchDFS e e [C, ...]      -- match expression\n    | Something                  -- Something built-in matcher\n\nC ::= [mc| p -\u003e e |]             -- match clause\n\np ::= _                          -- wildcard pattern\n    | $v                         -- pattern variable\n    | #e                         -- value pattern\n    | ?e                         -- predicate pattern\n    | (p_1, p_2, ..., p_n)       -- tuple pattern\n    | [p_1, p_2, ..., p_n]       -- collection pattern\n    | p \u0026 p                      -- and-pattern\n    | p | p                      -- or-pattern\n    | !p                         -- not-pattern\n    | c p_1 p_2 ... p_n          -- constructor pattern\n```\n\n## Usage\n\n### The `matchAll` expression and matchers\n\nThe `matchAll` expression evaluates the body of the match clause for all the pattern-matching results.\nThe expression below pattern-matches a target `[1,2,3]` as a list of integers with a pattern `cons $x $xs`.\nThis expression returns a list of a single element because there is only one decomposition.\n\n```hs\nmatchAll [1,2,3] (List Integer) [[mc| $x : $xs -\u003e (x, xs)|]]\n-- [(1,[2,3])]\n```\n\nThe other characteristic of `matchAll` is its additional argument matcher.\nA matcher is a special object that retains the pattern-matching algorithms for each data type.\n`matchAll` takes a matcher as its second argument.\nWe can change a way to interpret a pattern by changing a matcher.\n\nFor example, by changing the matcher of the above `matchAll` from `List Integer` to `Multiset Integer`, the evaluation result changes as follows:\n\n```hs\nmatchAll [1,2,3] (Multiset Integer) [[mc| $x : $xs -\u003e (x, xs)|]]\n-- [(1,[2,3]),(2,[1,3]),(3,[1,2])]\n```\n\nWhen the `Multiset` matcher is used, `:` (the cons pattern) decomposes a target list into an element and the rest elements.\n\nThe pattern-matching algorithms for each matcher can be defined by users.\nFor example, the matchers such as `List` and `Multiset` can be defined by users.\nThe `Something` matcher is the only built-in matcher.\n`something` can be used for pattern-matching arbitrary objects but can handle only pattern variables and wildcards.\nThe definitions of `List` and `Multiset` are found [here](https://github.com/egison/egison-haskell/blob/master/src/Control/Egison/Matcher.hs).\nWe will write an explanation of this definition in future.\n\n### Non-linear pattern\n\nNon-linear pattern matching is another important feature of Egison pattern matching.\nNon-linear patterns are patterns that allow multiple occurrences of the same pattern variables in a pattern.\nFor example, the program below pattern-matches a list `[1,2,5,9,4]` as a multiset and extracts pairs of sequential elements.\nA non-linear pattern is effectively used for expressing the pattern.\n\n```hs\nmatchAll [1,2,5,9,4] (Multiset Integer) [[mc| $x : #(x+1) : _ -\u003e x|]]\n-- [1,4]\n```\n\n### The `match` expression\n\nThe `match` expression takes a target, a matcher, and match-clauses as the `matchAll` expression.\nThe `match` expression returns only the evaluation result of the first pattern-matching result.\n\n```hs\nmatch [1,2,5,9,4] (Multiset Integer) [[mc| $x : #(x+1) : _ -\u003e x|]]\n-- 1\n```\n\nThe `match` expression is simply implemented using `matchAll` as follows:\n\n```hs\nmatch tgt m cs = head $ matchAll tgt m cs\n```\n\n### `matchAllDFS` and `matchDFS`\n\nThe `matchAll` and `match` expressions traverse a search tree for pattern matching in breadth-first order.\nThe reason of the default breadth-first traversal is because to enumerate all the successful pattern-matching results even when they are infinitely many.\nFor example, all the pairs of natural numbers can be enumerated by the following `matchAll` expression:\n\n```hs\ntake 10 (matchAll [1..] (Set Integer)\n           [[mc| $x : $y : _ -\u003e (x, y) |]])\n-- [(1,1),(1,2),(2,1),(1,3),(2,2),(3,1),(1,4),(2,3),(3,2),(4,1)]\n```\n\nIf we change the above `matchAll` to `matchAllDFS`, the order of the pattern-matching results changes as follows:\n\n```hs\ntake 10 (matchAllDFS [1..] (Set Integer)\n           [[mc| $x : $y : _ -\u003e (x, y) |]])\n-- [(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10)]\n```\n\nThere are cases where depth-first traversal is suitable because the depth-first order of pattern-matching results is preferable.\nFurthermore, `matchAllDFS` is more efficient than `matchAll`.\nIt would be better to use `matchAllDFS` instead of `matchAll` when the both expressions can be used.\n\n### Matcher definitions\n\nThe users can define pattern-matching algorithms for each pattern by themselves.\n\npreparing...\n\n```hs\nmatchAll (1,2) UnorderedEqlPair [[mc| uepair $x $y -\u003e (x,y) |]]\n-- [(1,2),(2,1)]\n\nmatchAll (1,2) UnorderedEqlPair [[mc| uepair #2 $x -\u003e x |]]\n-- [1]\n```\n\nA matcher is represented as a data type whose name and constructor's name is identical.\n\npreparing...\n\n```hs\ndata UnorderedEqlPair = UnorderedEqlPair\ninstance (Eq a) -\u003e Matcher UnorderedEqlPair (a, a)\n\nuepair :: (Eq a)\n       =\u003e Pattern a Eql ctx xs\n       -\u003e Pattern a Eql (ctx :++: xs) ys\n       -\u003e Pattern (a, a) UnorderedEqlPair ctx (xs :++: ys)\nuepair p1 p2 = Pattern (\\_ UnorderedEqlPair (t1, t2) -\u003e\n                          [twoMAtoms (MAtom p1 Eql t1) (MAtom p2 Eql t2)\n                          ,twoMAtoms (MAtom p1 Eql t2) (MAtom p2 Eql t1)])\n```\n\n```hs\nmatchAll (1,2) (UnorderedPair Eql) [[mc| uepair $x $y -\u003e (x,y) |]]\n-- [(1,2),(2,1)]\n\nmatchAll (1,2) (UnorderedPair Eql) [[mc| upair #2 $x -\u003e x |]]\n-- [1]\n```\n\n```hs\ndata UnorderedPair m = UnorderedPair m\ninstance Matcher m a =\u003e Matcher (UnorderedPair m) (a, a)\n\nupair :: (Matcher m a , a ~ (b, b), m ~ (UnorderedPair m'), Matcher m' b)\n      =\u003e Pattern b m' ctx xs\n      -\u003e Pattern b m' (ctx :++: xs) ys\n      -\u003e Pattern a m ctx (xs :++: ys)\nupair p1 p2 = Pattern (\\_ (UnorderedPair m') (t1, t2) -\u003e\n                         [twoMAtoms (MAtom p1 m' t1) (MAtom p2 m' t2)\n                         ,twoMAtoms (MAtom p1 m' t2) (MAtom p2 m' t1)])\n```\n\n## Samples\n\n### Twin primes\n\nWe can extract all twin primes from the list of prime numbers by pattern matching:\n\n```hs\ntake 10 (matchAll primes (List Integer)\n           [[mc| _ ++ $p : #(p+2) : _ -\u003e (p, p+2) |]])\n-- [(3,5),(5,7),(11,13),(17,19),(29,31),(41,43),(59,61),(71,73),(101,103),(107,109)]\n```\n\nIt is also possible to enumerate all the pairs of prime numbers whose form is (p, p+6):\n\n```hs\ntake 10 (matchAll primes (List Integer)\n           [[mc| _ ++ $p : _ ++ #(p+6) : _ -\u003e (p, p+6) |]])\n-- [(5,11),(7,13),(11,17),(13,19),(17,23),(23,29),(31,37),(37,43),(41,47),(47,53)]\n```\n\n### Poker hand\n\n```hs\npoker cs =\n  match cs (Multiset CardM)\n    [[mc| card $s $n :\n           card #s #(n-1) :\n            card #s #(n-2) :\n             card #s #(n-3) :\n              card #s #(n-4) :\n               [] -\u003e \"Straight flush\" |],\n     [mc| card _ $n :\n           card _ #n :\n            card _ #n :\n             card _ #n :\n              _ :\n               [] -\u003e \"Four of a kind\" |],\n     [mc| card _ $m :\n           card _ #m :\n            card _ #m :\n             card _ $n :\n              card _ #n :\n               [] -\u003e \"Full house\" |],\n     [mc| card $s _ :\n           card #s _ :\n            card #s _ :\n             card #s _ :\n              card #s _ :\n               [] -\u003e \"Flush\" |],\n     [mc| card _ $n :\n           card _ #(n-1) :\n            card _ #(n-2) :\n             card _ #(n-3) :\n              card _ #(n-4) :\n               [] -\u003e \"Straight\" |],\n     [mc| card _ $n :\n           card _ #n :\n            card _ #n :\n             _ :\n              _ :\n               [] -\u003e \"Three of a kind\" |],\n     [mc| card _ $m :\n           card _ #m :\n            card _ $n :\n             card _ #n :\n              _ :\n               [] -\u003e \"Two pair\" |],\n     [mc| card _ $n :\n           card _ #n :\n            _ :\n             _ :\n              _ :\n               [] -\u003e \"One pair\" |],\n     [mc| _ -\u003e \"Nothing\" |]]\n```\n\n## Benchmark\n\nWe benchmarked this library using the program that enumerates the first 50 (p, p+6) primes.\nThis Haskell library is much faster than the original Egison interpreter!\n\n```\n$ cabal new-bench prime-pairs\n...\nbenchmarking (p, p+6) pairs/50/egison\ntime                 5.066 s    (4.610 s .. 5.608 s)\n                     0.999 R²   (0.995 R² .. 1.000 R²)\nmean                 4.932 s    (4.807 s .. 5.017 s)\nstd dev              120.2 ms   (34.72 ms .. 161.7 ms)\nvariance introduced by outliers: 19% (moderately inflated)\n\nbenchmarking (p, p+6) pairs/50/miniEgison\ntime                 2.415 ms   (2.264 ms .. 2.527 ms)\n                     0.984 R²   (0.975 R² .. 0.991 R²)\nmean                 2.196 ms   (2.106 ms .. 2.266 ms)\nstd dev              252.3 μs   (219.0 μs .. 296.6 μs)\nvariance introduced by outliers: 73% (severely inflated)\n...\n```\n\n## Sponsors\n\nEgison is sponsored by [Rakuten, Inc.](http://global.rakuten.com/corp/) and [Rakuten Institute of Technology](http://rit.rakuten.co.jp/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegison%2Fegison-haskell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fegison%2Fegison-haskell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegison%2Fegison-haskell/lists"}