packages feed

alloy-1.0.0: tutorial/EffectsSelective.lhs

We can now put together two of our previous examples, to selectively increase
the salary of all those not in the research department, up to a given budget:


\begin{code}
{-# LANGUAGE TypeOperators #-}
import CompanyDatatypes
import Data.Generics.Alloy
import Instances
import Control.Monad.State

increaseAllButResearch :: Float -> Company -> Company
increaseAllButResearch k c = evalState (makeRecurseM ops c) 15000
  where
    ops :: (Dept :-* Salary :-* BaseOpA) (State Float)
    ops = doDept :-* incS k :-* baseOpA

    doDept :: Dept -> State Float Dept
    doDept d@(D name _ _)
      | name == "Research" = return d
      | otherwise = makeDescendM ops d

incS :: Float -> Salary -> State Float Salary
incS k (S s)
  = do budget <- get
       if diff > budget
         then return (S s)
         else do put $ budget - diff
                 return (S s')
  where
    s' = s * (1+k)
    diff = s' - s

main = print $ increaseAllButResearch 0.1 genCom
\end{code}%$

The changes in the \lstinline|increaseAllButResearch| function are that the
\lstinline|:-| constructor has become \lstinline|:-*| in the effectful
version, and similarly \lstinline|baseOp| has become \lstinline|baseOpA|.  The
terminator is oblivious to whether the effect in question is an applicative
functor or a monad, hence there is only the \lstinline|A|-suffixed version.
The opset is then parameterised by the monad in question (the bracketing in
the type of \lstinline|ops| is important).

Apart from these small textual changes, it can be seen that the code is
roughly the same.