packages feed

smarties-1.2.1: examples/pronouns/Main.hs

{-# LANGUAGE TypeSynonymInstances #-}

module Main where


import           Control.Monad.Random
import           Data.List            (intercalate, mapAccumL)
import           Prelude
import           Smarties

data Pronoun = HeHim | SheHer | TheyThem | FooBar | Other | Undecided deriving (Eq, Show)

data Student = Student {
  assignedPronoun  :: Pronoun,
  preferredPronoun :: Pronoun,
  openlyChange     :: Bool,
  jeans            :: Int
} deriving (Show)

type School = [Student]
type PerceptionType = (School, Student)
type ActionType = (Student -> Student)

assignedPronounIs :: Pronoun -> Student -> Bool
assignedPronounIs p s = assignedPronoun s == p

preferredPronounIs :: Pronoun -> Student -> Bool
preferredPronounIs p s = preferredPronoun s == p

feminimity :: Student -> Float
feminimity = fst . randomR (0.0,1.0) . mkStdGen . (+0) . jeans

masculinity :: Student -> Float
masculinity = fst . randomR (0.0,1.0) . mkStdGen . (+1) . jeans

chromeXX :: Student -> Bool
chromeXX = (<50) . fst . randomR ((0,100)::(Int,Int)) . mkStdGen . (+2) . jeans

chromeXY :: Student -> Bool
chromeXY = (>50) . fst . randomR ((0,100)::(Int,Int)) . mkStdGen . (+2) . jeans

chromeNeither :: Student -> Bool
chromeNeither s = not (chromeXX s) && not (chromeXY s)

noneOfTheAbove :: Student -> Float
noneOfTheAbove = fst . randomR (0.0,1.0) . mkStdGen . (+3) . jeans

developer :: Student -> Float
developer = fst . randomR (0.0,1.0) . mkStdGen . (+4) . jeans

indecisiveness :: Student -> Float
indecisiveness = fst . randomR (0.0,1.0) . mkStdGen . (+5) . jeans

-- totally cool if she or he keeps it him or herself ;)
-- for the purpose of this demo, this is determined by the kind of jeans a student wears. This is not true IRL.
dogmaticBeliefInBinaryBiologicalDeterminism :: Student -> Bool
dogmaticBeliefInBinaryBiologicalDeterminism s = b s && not (chromeNeither s) where
  b = (>99) . fst . randomR ((0,100)::(Int,Int)) . mkStdGen . (+2) . jeans

toZeroOne :: Bool -> Float
toZeroOne x = if x then 1.0 else 0.0

actionChangePronoun :: Pronoun -> NodeSequence g PerceptionType ActionType ()
actionChangePronoun p = fromAction $
  SimpleAction (\_ -> (\(Student a _ _ d) -> Student a p True d))

actionChangeBack :: NodeSequence g PerceptionType ActionType ()
actionChangeBack = fromAction $
  SimpleAction (\_ -> (\(Student a _ c d) -> Student a a c d))

conditionHasProperty :: (Student -> Bool) -> NodeSequence g PerceptionType ActionType ()
conditionHasProperty f = fromCondition $
  SimpleCondition (\(_, st) -> f st)

utilityProperty :: (Student -> Float) -> NodeSequence g PerceptionType ActionType Float
utilityProperty f = fromUtility $
  SimpleUtility (\(_, st) -> f st)

utilityNormalness :: (Student -> Float) -> NodeSequence g PerceptionType ActionType Float
utilityNormalness f = fromUtility $
  SimpleUtility (\(sc, _) -> (sum (map f sc)) / fromIntegral (length sc))

studentTree :: (RandomGen g) => NodeSequence g PerceptionType ActionType Float
studentTree = utilityWeightedSelector
  [return . (*0.2) . (+0.01) =<< utilityWeightedSelector
    [do
      a <- utilityNormalness (toZeroOne . openlyChange)
      b <- utilityProperty feminimity
      actionChangePronoun SheHer
      return $ a * b
    ,do
      a <- utilityNormalness (toZeroOne . openlyChange)
      b <- utilityProperty masculinity
      actionChangePronoun HeHim
      return $ a * b
    ,do
      a <- utilityNormalness (toZeroOne . openlyChange)
      b <- utilityProperty developer
      actionChangePronoun FooBar
      return $ a * b
    ,do
      a <- utilityNormalness (toZeroOne . openlyChange)
      b <- utilityProperty noneOfTheAbove
      actionChangePronoun Other
      return $ a * b
    ,do
      a <- utilityNormalness (toZeroOne . openlyChange)
      m <- utilityProperty masculinity
      f <- utilityProperty feminimity
      actionChangePronoun TheyThem
      return $ a * ((1.0-m)+(1.0-f)) / 2.0
    ]
  ,do
    a <- utilityProperty indecisiveness
    actionChangeBack
    return $ 0.01 * a
  ,do
    a <- utilityNormalness ((1-) . toZeroOne . openlyChange)
    result SUCCESS
    return a
  ]

makeStudent :: (RandomGen g) => Rand g Student
makeStudent = do
  (sJeans::Int) <- getRandom
  (isFemale::Bool) <- getRandom
  let
    pronoun = if isFemale then SheHer else HeHim
  return $ Student pronoun pronoun False sJeans

main :: IO ()
main = do
  stdgen <- getStdGen
  students <- replicateM 10 $ evalRandIO makeStudent
  let
    studentfn g s = (g', (foldl (.) id os) s) where
      (g', _, _, os) = execNodeSequence studentTree g (students, s)
    ticktStudents g sts = mapAccumL studentfn g sts
    loop (0::Int) _ sts = return sts
    loop n g sts = do
      let (g', nextsts) = ticktStudents g sts
      putStrLn . show $ (sum . map (toZeroOne . openlyChange) $ nextsts) --  / (fromIntegral $ length nextsts)
      loop (n-1) g' nextsts
  sts <- loop 365 stdgen students
  putStrLn $ intercalate "\n" $ map (\s -> show (preferredPronoun s) ++ " " ++ show (assignedPronoun s) ++ " " ++ show (openlyChange s)) sts