packages feed

MultiChor-1.0.0.0: examples/Data.hs

{-# LANGUAGE FunctionalDependencies #-}

module Data where

import Data.Time (Day (ModifiedJulianDay), fromGregorian)
import Test.QuickCheck (Arbitrary, Positive (Positive), arbitrary, arbitraryPrintableChar, elements, getPositive, listOf1)

data Book = Book
  { name :: String,
    price :: Int,
    deliverable :: Day
  }
  deriving (Eq, Read, Show)

instance Arbitrary Book where
  arbitrary =
    Book
      <$> listOf1 arbitraryPrintableChar
      <*> (getPositive <$> arbitrary)
      <*> (ModifiedJulianDay . getPositive <$> arbitrary)

type Database = [Book]

textbooks :: Database
textbooks =
  [ Book
      { name = "Types and Programming Languages",
        price = 80,
        deliverable = fromGregorian 2023 12 19
      },
    Book
      { name = "Homotopy Type Theory",
        price = 120,
        deliverable = fromGregorian 2023 09 18
      }
  ]

priceOf :: Database -> String -> Int
priceOf books title = price $ head $ filter ((== title) . name) books

deliveryDateOf :: Database -> String -> Day
deliveryDateOf books title = deliverable $ head $ filter ((== title) . name) books

data BooksellerArgs = BooksellerArgs
  { books :: Database,
    choice :: String,
    budget :: Int
  }
  deriving (Read, Show)

instance Arbitrary BooksellerArgs where
  arbitrary = do
    books <- listOf1 arbitrary
    choice <- name <$> elements books
    budget <- getPositive <$> arbitrary
    return BooksellerArgs {books, choice, budget}

class TestArgs a r | a -> r where
  reference :: a -> r

instance TestArgs BooksellerArgs (Maybe Day) where
  reference (BooksellerArgs {books, choice, budget}) =
    if budget < priceOf books choice
      then Nothing
      else Just $ deliveryDateOf books choice

instance TestArgs (BooksellerArgs, Positive Int) (Maybe Day) where
  reference (BooksellerArgs {books, choice, budget}, Positive contrib) =
    if budget < (priceOf books choice - contrib)
      then Nothing
      else Just $ deliveryDateOf books choice

-- a scenario where there's four buyers (one primary and three supporter)
instance TestArgs (BooksellerArgs, Positive Int, Positive Int, Positive Int) (Maybe Day) where
  reference (BooksellerArgs {books, choice, budget}, Positive contrib, Positive contrib2, Positive contrib3) =
    if budget < (priceOf books choice - contrib - contrib2 - contrib3)
      then Nothing
      else Just $ deliveryDateOf books choice