{-# LANGUAGE TypeFamilies, FlexibleContexts, ScopedTypeVariables #-}

{-|
Module      : Database.HaskRel.Relational.Unicode
Description : Functions pertaining to relational theory or set theory named with
              unicode characters
Copyright   : © Thor Michael Støre, 2015
License     : GPL v2 without "any later version" clause
Maintainer  : thormichael át gmail døt com
Stability   : experimental

Functions pertaining to relational theory or set theory named with non-ASCII
unicode characters, primarily infix operators. Each of these is a synonym for an
alphabetically named prefix function.

See also: http://hackage.haskell.org/package/base-unicode-symbols

TODO: Fix operator precedence, right now one may need to apply more parenthesis
than should be necessary.
-}

module Database.HaskRel.Relational.Unicode (
  -- * Relational algebra operators
  (), (), (), (), (), (×), (), (), (), (), π,
  (), (), (), (), 
  -- * Relational assignment operators
  (),
  -- * Supplementary relational operators
  -- **** Not part of relational theory
  (), 
  -- * Set theoretic operators
  (#), (), (), (), (), ()
) where

import Database.HaskRel.Relational.Definition ( Relation, bodyAsList, empty )
import Database.HaskRel.Relational.Expression
import Database.HaskRel.Relational.Variable ( Relvar, writeRelvarBody' )


import Data.Set ( Set )
import Data.HList.CommonMain

{-| Natural join.

>>> rPrint$ sp ⋈ s
...

As 'Database.HaskRel.Relational.Expression.naturalJoin'.
-}
r1  r2 = naturalJoin r1 r2

{-| Semijoin.

>>> rPrint$ s ⋉ sp
...

As 'Database.HaskRel.Relational.Expression.matching'.
-}
r1  r2 = semiJoin r1 r2

-- | Left semijoin. As @(flip 'Database.HaskRel.Relational.Expression.matching')@.
r1  r2 = semiJoin r2 r1


{-| Semidifference.

>>> rPrint$ s ◅ sp
...

As 'Database.HaskRel.Relational.Expression.notMatching'.
-}
r1  r2 = notMatching r1 r2

-- | Left semidifference. As @(flip 'Database.HaskRel.Relational.Expression.notMatching')@.
r1  r2 = notMatching r2 r1

{-| Times. The special case of natural join where the headings of the relations
are disjoint.

>>> rPrint$ ( sp `projectAllBut` (rHdr (sno)) ) × ( s `projectAllBut` (rHdr (sno)) )
...

As 'Database.HaskRel.Relational.Expression.times'.
-}
l × r = times l r

{-| Attribute intersecting natural join. The special case of natural join where
the headings of the relations are not disjoint.

Using the "box times" or "squared times" (U+22A0) symbol is my own solution. As
with the name "(attribute) intersecting natural join" suggestions are welcome.

As mentioned in "Database.HaskRel.Relational.Algebra", this operation doesn't
have a single identity value, although it holds that for any given relation
value @r@, @r ⊠ r = r@

>>> rPrint$ sp ⊠ s
...

As 'Database.HaskRel.Relational.Expression.interJoin'.
-}
l  r = interJoin l r


{-| Restriction.

Note that the symbol used here is the divisor symbol, which looks the same but
is distinct from the vertical bar, or pipe. However, since the vertical bar is
used in Haskell for different purposes and is for that reason not a valid infix
operator symbol, this is used instead.

>>> rPrint$ p ∣ (\[pun|weight|] -> weight < 17.5)
...

As 'Database.HaskRel.Relational.Expression.restrict'.
-}
r  p = restrict r p

{-| Union.

>>> rPrint$ s ∪ ( relation [rTuple (sno .=. "S6", sName .=. "Nena", status .=. 40, city .=. "Berlin")] )
...

As 'Database.HaskRel.Relational.Expression.union'.
-}
l  r = l `union` r

{-| Intersection.

>>> let sX = ( relation [rTuple (sno .=. "S2", sName .=. "Jones", status .=. 10, city .=. "Paris"), rTuple (sno .=. "S6", sName .=. "Nena", status .=. 40, city .=. "Berlin")] )
>>> rPrint$ s ∩ sX
...

As 'Database.HaskRel.Relational.Expression.intersect'.
-}
l  r = l `intersect` r

{-| Minus.

Note that this is the difference symbol, not a backslash.

>>> rPrint$ s ∖ sX
...

As 'Database.HaskRel.Relational.Expression.minus'.
-}
l  r = minus l r

{-| Projection.

Note that no matter how greek it is π is still a character, and Haskell
therefore treats it as a prefix operator, which is in line with how it is
employed.

>>> rPrint$ π (rHdr (color,city)) p
...

As 'Database.HaskRel.Relational.Expression.project', but note how the operands
are reversed.
-}
π a r  = project r a

infix 1 

{-|
Relational assignment operator.

This uses the COLON EQUALS UTF-8 character (\&\#8788;), the ASCII variant @ := @
wouldn't be allowed in Haskell since it starts with a colon.

>>> s ≔ s'
>>>

As 'Database.HaskRel.Relational.Expression.assign'.
-}
() rv r = assign rv r


{-| Is proper subset.

>>> let spX = relation [rTuple (sno .=. "S1", pno .=. "P4", qty .=. 200), rTuple (sno .=. "S2", pno .=. "P2", qty .=. 400)]
>>> spX ⊂ sp
True

As 'Database.HaskRel.Relational.Expression.isProperSubsetOf'.
-}
l  r = isProperSubsetOf l r

{-| Is subset of.

>>> spX ⊆ sp
True

As 'Database.HaskRel.Relational.Expression.isSubsetOf'.
-}
l  r = isSubsetOf l r

-- | Left is proper subset of. As @(flip 'Database.HaskRel.Relational.Expression.isProperSubsetOf')@.
l  r = isProperSubsetOf r l

-- | Left is subset of. As @(flip 'Database.HaskRel.Relational.Expression.isSubsetOf')@.
l  r = isSubsetOf r l

{-| Cardinality.

>>> (#) sp
12

As 'Database.HaskRel.Relational.Expression.count'.
-}
(#) r = count r


{-| Is member of.

>>> let spX = rTuple(sno .=. "S3", qty .=. 200, pno .=. "P2")
>>> spX ∈ sp
True

As 'Database.HaskRel.Relational.Expression.member'.
-}
l  r = member l r

{-| Is not member of.

>>> spX ∉ sp
False

As 'Database.HaskRel.Relational.Expression.notMember'.
-}
l  r = notMember l r

-- | Is member of left. As @(flip 'Database.HaskRel.Relational.Expression.member')@.
r  e = member e r

-- | Is not member of left. As @(flip 'Database.HaskRel.Relational.Expression.notMember')@.
r  e = notMember e r

{- | The empty set. Note that this is neither 'tableDum' nor 'tableDee'.

>>> (relation [] :: Relation '[]) == (∅)
True
>>> relation [rTuple (sno .=. "S1", status .=. 5)] == (∅)
False
-}
() = empty

{-
Other infix operators
∖ minus/relative complement/set-theoretic difference - don't confuse with blackslash - \ - you may need to use a different font to see the difference.
 # cardinality - prefix, needs parenthesis
∅ empty set
∆ or ⊖ symmetric difference
π relational projection
◅ ▻ antijoin
σ selection
‼ image relation
:= or ≔ relational assignment

Predicate logic, although the Haskell library http://hackage.haskell.org/package/base-unicode-symbols already uses them:
∀ Forall
∃ Exists

Other common and useful operators of arithmetry and whatnot:
±
≬ between
≺ preceeds
≻ suceeds

See also:
http://en.wikipedia.org/wiki/List_of_mathematical_symbols
http://www.fileformat.info/info/unicode/block/mathematical_operators/images.htm
-}