-- | Tuple construction/destruction

module Feldspar.Core.Functions.Tuple where



import Feldspar.DSL.Expression
import Feldspar.DSL.Lambda
import Feldspar.DSL.Network
import Feldspar.Core.Types
import Feldspar.Core.Representation
import Feldspar.Core.Constructs



pair :: (Type a, Type b) => Data a -> Data b -> Data (a,b)
pair (Data a) (Data b) = case (undoEdge a, undoEdge b) of
             (  Inject (Node (Function "getFst" _)) :$: a'
              , Inject (Node (Function "getSnd" _)) :$: b'
              ) | exprEq a' b', Just ab <- exprCast b' -> Data ab
             _ -> nodeData (edgeSize $ edgeInfo a, edgeSize $ edgeInfo b) $ Inject (Node Pair) :$: a :$: b

getFst :: (Type a, Type b) => Data (a,b) -> Data a
getFst (Data ab) = case undoEdge ab of
    Inject (Node Pair) :$: a :$: _ -> Data a
    _ -> function1 "getFst" fst fst (Data ab)

getSnd :: (Type a, Type b) => Data (a,b) -> Data b
getSnd (Data ab) = case undoEdge ab of
    Inject (Node Pair) :$: _ :$: b -> Data b
    _ -> function1 "getSnd" snd snd (Data ab)

-- | Convenient together with view patterns:
--
-- > f :: Data (a,b) -> ...
-- > f (matchPair -> (a,b)) = ...
matchPair :: (Type a, Type b) => Data (a,b) -> (Data a, Data b)
matchPair ab = (getFst ab, getSnd ab)