Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You can do exactly what you want using GADTs (Generalized Algebraic Data Types) and existentials (the "forall a." below). The type "Strategy" hides the internal type "a" which is an implementation detail. Pattern matching in the call to "go" brings all the pieces of Strategy into scope. Note that I used GHC's RecordWildCards "{..}" to save my fingers. This compiles because "go" does not return anything that exposes the internal type "a".</p> <p>Much more detail exists in the <a href="http://www.haskell.org/ghc/docs/latest/html/users_guide/index.html" rel="nofollow">GHC User Manual</a>.</p> <pre><code>{-# LANGUAGE GADTs, RankNTypes, RecordWildCards #-} import Control.Monad.State type Code = [Int] data Answer = Answer { blacks :: Int, whites :: Int } deriving (Eq, Show) data Strategy where Strategy :: forall a. { strategyName :: String , firstGuess :: Int -&gt; Code , initialize :: Int -&gt; a , guess :: Answer -&gt; State a Code } -&gt; Strategy dummy = Strategy { strategyName = "dummy" , firstGuess = firstGuess' , initialize = initialize' , guess = guess' } -- | The very first guess is always T0,T1,...,Tx, where x is the code length. firstGuess' :: Int -&gt; Code firstGuess' length = [0..length-1] -- | Memorize the code length initialize' :: Int -&gt; Int initialize' = id -- | Always return the same guess guess' :: Answer -&gt; State Int Code guess' = const $ liftM firstGuess' get -- Take size and strategy and compute number of steps to win -- modified to create local type variable 'a' to write type for 'step' go :: Code -&gt; Strategy -&gt; (String,Int) go secretCode (Strategy {initialize=initialize::Int-&gt;a,..}) = let size = length secretCode nextAnswer :: Code -&gt; Maybe Answer nextAnswer _ = undefined {- compare with secretCode -} step :: Code -&gt; Int -&gt; State a (String,Int) step code n = case nextAnswer code of Nothing -&gt; return (strategyName,n) Just answer -&gt; do code' &lt;- guess answer step code' $! (succ n) in evalState (step (firstGuess size) 0) (initialize size) </code></pre> <p>And by using a WriterT I could add a log of the guesses:</p> <pre><code>-- Take size and strategy and compute number of steps to win goW :: Code -&gt; Strategy -&gt; ((String,Int),[(Code,Answer)]) goW secretCode (Strategy {..}) = let size = length secretCode nextAnswer :: Code -&gt; Maybe Answer nextAnswer _ = undefined {- compare with secretCode -} step code n = case nextAnswer code of Nothing -&gt; return (strategyName,n) Just answer -&gt; do code' &lt;- lift (guess answer) tell [(code,answer)] step code' $! (succ n) in evalState (runWriterT (step (firstGuess size) 0)) (initialize size) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload