In Ihrem Fall ist es ein Striktheitsproblem, das den Stapelüberlauf verursacht. Eine wirklich einfache Möglichkeit, solche Probleme zu finden, ist die Verwendung der deepseq library. Dies fügt ein paar Funktionen hinzu, mit denen Sie einen Wert vollständig auswerten können (was besser ist als seq
, was nur eine Ebene tiefer geht). Die Schlüsselfunktion ist force :: NFData a => a -> a
. Dies nimmt einen Wert, bewertet es vollständig und gibt es zurück.
Es funktioniert jedoch nur auf Typen, die die Klassenklasse NFData
implementieren. Glücklicherweise gibt es ein Template-Haskell-Makro im deepseq-th library: deriveNFData
. Dies wird mit Ihren eigenen Datentypen verwendet, zB deriveNFData ''BfMachine
.
Um zu verwenden, setzen Sie force $
vor Ihren Funktionen, die Strenge Probleme haben können (oder liftM force $
für monadische Funktionen).ZB mit Ihrem Code, ich habe es vor step
, denn das ist die Schlüsselfunktion in der Datei war:
{-# LANGUAGE TemplateHaskell #-}
import Data.Char
import Debug.Trace
import Control.DeepSeq
import Control.DeepSeq.TH
import Control.Monad (liftM)
type Stack = [Int]
data BfMachine = BfMachine
{ program :: String
, pc :: Int
, stack :: Stack
, sp :: Int
} deriving Show
deriveNFData ''BfMachine
setElem :: [Int] -> Int -> Int -> [Int]
setElem list n value = map (\(i, v) -> if i == n then value else v) (zip [0..] list)
step :: BfMachine -> IO (BfMachine)
step [email protected](BfMachine { program = program, pc = pc, stack = stack, sp = sp }) = liftM force $
case program !! pc of
'-' -> return m { pc = pc + 1, stack = setElem stack sp ((stack !! sp) - 1) }
'+' -> return m { pc = pc + 1, stack = setElem stack sp ((stack !! sp) + 1) }
'<' -> return m { pc = pc + 1, sp = sp - 1 }
'>' -> return m { pc = pc + 1, sp = sp + 1 }
'[' -> return $ if stack !! sp /= 0 then m { pc = pc + 1 }
else m { pc = (findNextBracket program $ pc + 1) + 1 }
']' -> return m { pc = findPrevBracket program $ pc - 1 }
'.' -> do putChar $ chr $ stack !! sp
return m { pc = pc + 1 }
',' -> do c <- getChar
let s' = setElem stack sp $ ord c
in return m { stack = s', pc = pc + 1 }
a -> return m { pc = pc + 1 }
findNextBracket :: String -> Int -> Int
findNextBracket program pos =
case program !! pos of
'[' -> findNextBracket program $ (findNextBracket program $ pos + 1) + 1
']' -> pos
x -> findNextBracket program (pos + 1)
findPrevBracket :: String -> Int -> Int
findPrevBracket program pos =
case program !! pos of
']' -> findPrevBracket program $ (findPrevBracket program $ pos - 1) - 1
'[' -> pos
x -> findPrevBracket program (pos - 1)
isFinished :: BfMachine -> Bool
isFinished [email protected](BfMachine { program = p, pc = pc })
| pc == length p = True
| otherwise = False
run :: BfMachine -> IO()
run m = do
if isFinished m then
return()
else do
m <- step m
run m
fib = ">++++++++++>+>+[ [+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[ [-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<- [>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>> ]<<< ] This program doesn't terminate; you will have to kill it. Daniel B Cristofani (cristofdathevanetdotcom) http://www.hevanet.com/cristofd/brainfuck/"
main = run BfMachine { program = fib , pc = 0, stack = replicate 1024 0, sp = 0 }
Dies löst das Problem tatsächlich - auch nach einem paar Minuten laufen, es ist nicht abgestürzt und Speicher Die Nutzung ist nur 3,2 MB.
Sie können mit dieser Lösung bleiben, oder versuchen zu finden, wo das echte Striktheitsproblem ist (wie das macht alles streng). Sie tun dies, indem Sie die Kraft von der step
Funktion entfernen und es auf den Hilfsfunktionen versuchen, die es benutzt (zB setElem
, findPrevBacket
, usw.). Es stellt sich heraus, dass setElem
der Schuldige ist, setzen force
vor dieser Funktion auch das Striktheitsproblem löst. Ich vermute, es ist, weil die if
in der Map Lambda bedeutet, dass die meisten Werte nie in der Liste ausgewertet werden müssen und möglicherweise riesige Thunks aufbauen, während das Programm weitergeht.
Wie haben Sie kompiliert? ghc -O2 blah.hs kann vielleicht besser optimieren –
Danke, aber es hat nicht geholfen – Philippe
könnten Sie einen Pastebin Link zum Code bereitstellen? – jev