2017-04-04 2 views
0

Ich habe versucht, einen Haskell-Spielcode zu kompilieren, dieser Code generiert drei Threads, einen für Endlosschleife, einen für das Sammeln der Benutzerinteraktion, einen für das Auslösen der Ereignisse. Der Code kann jedoch nicht kompiliert werden und ich weiß nicht warum.Warum dieser Hakell-Code nicht kompiliert werden kann

Hier ist der Code:

module Main where 

import Control.Concurrent 
import Control.Monad 
import System.IO 
import System.Random 
import Text.Printf 

data Msg = C Char | Time 
data Event = C Char | Time Char 

main :: IO() 
main = do 
    hSetBuffering stdout NoBuffering 
    hSetBuffering stdin NoBuffering 
    hSetEcho stdin False 

    -- shared resources 
    chan <- newEmptyMVar 
    removedDigits <- newEmptyMVar 
    unmatchedDigits <- newEmptyMVar 
    numberOfGuesses <- newEmptyMVar 

    --starting the generating thread and the user thread 
    forkIO $ generatingThread chan 
    forkIO $ userThread chan 

    --the main loop 
    if mainloop chan == True then "Congratulations! You won!" else "Better luck next time!" 
    return() 

    mainloop :: Chan c -> Bool 
    let mainloop = do 
    if length unmatchedDigits >= 10 
    then return False 
    Event <- readChan c 
    if Event == "timer" 
    then unmatchedDigits ++ param 
    else if testGuessedNumber param unmatchedDigits == True 
     then 
     removeMatchedDigit 
     if length unmatchedDigits == 0 
     then return True 
    mainloop c 

-- Generating Thread aka event thread generating the random numbers 
generatingThread :: Chan msgChan -> IO() 
generatingThread msgChan = forever $ do 
    publishTimerEvent msgChan 1000000 

publishTimerEvent :: Chan msgChan -> Int delay() 
publishTimerEvent msgChan = do 
    c <- getRandomChar 
    putMVar msgChan ("timer" c) 
    threadDelay newDelay 
    velocity <- 0.9 
    if delay * velocity < 100 
    then newDelay <- 100 
    else newDelay <- delay * velocity 
    publishTimerEvent msgChan newDelay 

getRandomChar :: Char c() 
getRandomChar = do 
    i <- randomRIO (0,9) 
    let c = "" !! i 
    return c 

-- User Thread 
userThread :: MVar Msg -> IO() 
userThread chan = forever $ do 
    c <- getChar 
    putMVar chan (C c) 
    showStr(show c) 

testGuessedNumber :: Int -> Int -> Bool 
testGuessedNumber a b 
    | a == b = True 
    | otherwise = False 

-- Shows the given string at the left edge of the current terminal line after 
-- having blanked out the first 20 characters on that line. 
showStr :: String -> IO() 
showStr s = putStr ("\r" ++ replicate 20 ' ' ++ "\r" ++ s) 

Der Fehler ist "test.hs: 36: 3: Fehler: Parsen Fehler bei der Eingabe 'Ereignis'"

+2

Welche Fehlermeldung erhalten Sie, wenn Sie versuchen, den Code zu kompilieren? – jwodder

+4

Hallo, Jason, und willkommen bei Stack Overflow. Obwohl Sie gut erklärt haben, was Ihr Problem ist, wird es wahrscheinlich schwierig für Sie sein, eine gute Antwort zu bekommen, weil Ihr Code relativ groß ist, und es dauert eine Weile für jeden, der es beantworten könnte Finde die Teile, die das Problem verursachen könnten. Sie sollten selbst einige Tests durchführen, welche Teile des Codes mit größerer Wahrscheinlichkeit Probleme verursachen, und dann Ihre Frage mit einem [Minimalen, vollständigen und überprüfbaren Beispiel] (https://stackoverflow.com/help/mcve). So können Sie sicherstellen, dass Sie qualitativ hochwertige Antworten erhalten. –

+0

Danke, der Fehler ist "test.hs: 36: 3: Fehler: Parse Fehler bei Eingabe 'Event'". – Jason

Antwort

1

Variablennamen mit Großbuchstaben nicht beginnen kann, wie Event. Versuchen Sie, die Variable in etwas wie event umzubenennen.

+0

Während korrekt, das ist nicht das Problem. Sie könnten mit dem Datenkonstruktor "Event" in einer Do-notation-Bindung übereinstimmen. – Lazersmoke

0

In Haskell müssen alle if ... then ... else Blöcke alle ihre Komponenten haben; Was wäre das Ergebnis sonst?

Das Problem ist, dass der Compiler eine else erwartet, aber es tatsächlich Event. Das heißt, Sie haben mehr Probleme als ein einfacher Parse-Fehler. return tut nicht, was Sie denken, dass es tut. Dieser Code wird beispielsweise hi drucken.

main = do 
    return() 
    putStrLn "hi" 

Die return Funktion einfach einen Wert in eine Monade Aufzüge, es hört nicht auf die Berechnung oder so etwas. Hier ist, was Sie wahrscheinlich haben wollen:

... 
if length unmatchedDigits >= 10 
    then return False 
    else do 
    Event <- readChan c 
    if Event == "timer" 
     then ... 
     else ... 

Auf diese Weise passiert nichts nach dem if-Block, so dass die Funktion endet einfach da, mit dem letzten Wert als False (wenn length unmatchedDigits >= 10) oder weiter auf richtig (wenn length unmatchedDigits < 10).

Sie wollen auch fast sicher nicht Event (Großbuchstabe E) verwenden, weil das bedeutet, dass es ein Datenkonstruktor ist. Du meinst wahrscheinlich event (Kleinbuchstabe e), was nur ein gewöhnlicher Variablenname ist.

Zusätzlich: Dies ist sehr, sehr nicht-idiomatische Haskell. Sie definitiv brauchen nicht MVars in dieser Situation, und sicherlich nicht vier von ihnen. Chan s sind nicht das Gleiche wie MVar s, und Sie brauchen keines, es sei denn, Sie arbeiten mit Hochleistungs-Multithreading. I hoch empfehlen, dass Sie dies vollständig umschreiben und versuchen, die Menge an Code zu minimieren, der IO verwendet (es sollte vielleicht 10-15 Zeilen von IO Code in diesem Beispiel wahrscheinlich weniger).

Dies ist nicht Java; Sie müssen Ihre Variablen nicht in Ihrer Typsignatur (Chan msgChan -> Int delay()) benennen, und Sie müssen auch keine Wrapperfunktionen für Standardbibliotheksfunktionen schreiben, um deren Typ zu monomorphisieren. testGuessedNumber ist buchstäblich die gleiche Funktion wie(==).

Sie werden viel mehr Erfolg haben, wenn Sie die grundlegende, reine Funktionssyntax überprüfen und verstehen, wie Probleme in Haskell gelöst werden, als wenn Sie versuchen, eine andere Sprache zu emulieren. Lesen Sie einige LYAH oder Real World Haskell.

Verwandte Themen