module Datatypes where

import Prelude hiding (Maybe(..))

data T
  = A
  | B Int
  | C Bool String
  | D (Char, String)
      deriving (Show)

{-
tToInt             :: T -> Int
tToInt A           =  0
tToInt (B i)       =  1
tToInt (C b s)     =  2
tToInt (D (c, s))  =  3
-}

tToInt :: T -> Int
tToInt t =
  case t of
    A        -> 0
    B i      -> 1
    C b s    -> 2
    D (c, s) -> 3

--------------------------------------------------------------------------------

data Maybe a
  = Nothing
  | Just a
      deriving (Eq, Show)

maybeHead :: [a] -> Maybe a
maybeHead []     = Nothing
maybeHead (x:xs) = Just x

maybeTail :: [a] -> Maybe [a]
maybeTail []     = Nothing
maybeTail (x:xs) = Just xs

--------------------------------------------------------------------------------

data Unit = Unit deriving (Eq, Show)
data Pair a b = Pair a b deriving (Eq, Show)
data Triple a b c = Triple a b c deriving (Eq, Show)
data Tuple4 a b c d = Tuple4 a b c d deriving (Eq, Show)

--------------------------------------------------------------------------------

{-
data Bool
  = False
  | True
      deriving (Eq, Show)
-}

absoluteValue n =
  case n >= 0 of
    True   -> n
    False -> -n

--------------------------------------------------------------------------------

data List a
  = Nil
  | Cons a (List a)
      deriving (Eq, Show)

--------------------------------------------------------------------------------

yenPerDollar  = 112.86         -- as of 9/27/17
dollarsPerYen = 1 / yenPerDollar

{-
data Currency
  = USD Float   -- US Dollars
  | JPY Float   -- Japanese Yen
      deriving (Eq, Show)

add                    :: Currency -> Currency -> Currency
add (USD d1) (USD d2)  =  USD (d1 + d2)
add (JPY y1) (JPY y2)  =  JPY (y1 + y2)
add (USD d)  (JPY y)   =  USD (d + y * dollarsPerYen)
add (JPY y)  (USD d)   =  JPY (y + d * yenPerDollar)

convert :: Currency -> Currency
convert (USD d) = JPY (convertDollarsToYen d)
convert (JPY y) = USD (convertYenToDollars y)

convertYenToDollars :: Float -> Float
convertYenToDollars y = y * dollarsPerYen

convertDollarsToYen :: Float -> Float
convertDollarsToYen d = d * yenPerDollar
-}

data Currency
  = USD Dollars -- US Dollars
  | JPY Yen     -- Japanese Yen
  deriving (Eq, Show)

{-
data Dollars = DollarsFloat Float deriving (Eq, Show)
data Yen     = YenFloat Float deriving (Eq, Show)
-}

data Dollars = Dollars Float deriving (Eq, Show)
data Yen     = Yen Float deriving (Eq, Show)

add                    :: Currency -> Currency -> Currency
add (USD d1) (USD d2)  =  USD (addDollars d1 d2)
add (JPY y1) (JPY y2)  =  JPY (addYen y1 y2)
add (USD d)  (JPY y)   =  USD (addDollars d (convertYenToDollars y))
add (JPY y)  (USD d)   =  JPY (addYen y (convertDollarsToYen d))

addDollars :: Dollars -> Dollars -> Dollars
addDollars (Dollars d1) (Dollars d2) = Dollars (d1 + d2)

addYen :: Yen -> Yen -> Yen
addYen (Yen y1) (Yen y2) = Yen (y1 + y2)

convertYenToDollars :: Yen -> Dollars
convertYenToDollars (Yen y) = Dollars (y * dollarsPerYen)

convertDollarsToYen :: Dollars -> Yen
convertDollarsToYen (Dollars d) = Yen (d * yenPerDollar)

--------------------------------------------------------------------------------

data T'
  = A' 
  | B' Int
  | C' { foo :: Bool, baz :: String }
  | D' { bar :: Char, baz :: String }
      deriving (Show)
