This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Data.Generics(Data,Typeable) | |
import Prelude(Show,Read,Eq) | |
data Bit=T | F | |
deriving (Show,Read,Eq,Data,Typeable) | |
nand :: (Bit, Bit) -> Bit | |
nand (T,T)=F | |
nand _=T | |
not :: Bit -> Bit | |
not a=nand(a,T) |
Then I moved on to the other gates. It was interesting to think about boolean logic without Or, for example, after years of only reasoning in terms of And Or and Not. But at some stage I thought "why am I doing this by hand?". I remembered a thread about a new genetic programming library on an Haskell group. Surely generating the gates would be simple enough?
So I got genprog from hackage, and adapted the example for my needs. I started with a very simple system to determine the implementation of Not:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses #-} | |
module Gen where | |
import GenProg | |
import Data.Generics | |
import Control.Monad | |
import Control.Monad.Random | |
import Logic | |
data E=Nand E E | |
| Const Bit | |
| Param | |
deriving (Show,Eq,Data,Typeable) | |
eval :: E -> Bit -> Bit | |
eval (Nand e1 e2) p=nand (eval e1 p,eval e2 p) | |
eval (Const b) _=b | |
eval Param p=p | |
notFitness :: E -> Double | |
notFitness e=let | |
resF=eval e F | |
resT=eval e T | |
in if resF==T && resT==F | |
then ((realToFrac $ nodes e)*100) | |
else 100000000 | |
instance GenProg (Rand StdGen) E where | |
terminal = do | |
r<-getRandomR (0,2) | |
return $ [Const T,Const F,Param] !! r | |
nonterminal = liftM2 Nand terminal terminal | |
run=let | |
params = defaultEvolParams { fitness = notFitness } | |
g = mkStdGen 0 | |
in cachedBest $ evalRand (evolve params) g |
And of course, the result came quickly enough: not a=nand(a,a). No need for a Const at all! Evolution has beaten me! (OK, I'm only a not-so-intelligent designer, I suppose...)
Now, I'm going to see if this approach can take me all the way to the arithmetic unit...