2013-07-18 11 views
5

Sto avendo una piccola situazione Haskell qui. Sto cercando di scrivere due funzioni con le monadi. Prima si suppone di iterare attraverso una funzione fintanto che la condizione è vera per l'input/output della funzione. Il secondo dovrebbe usare il primo per prendere un numero come input e scriverlo come output finché non si entra in uno spazio.Durante il ciclo in Haskell con una condizione

Sono bloccato con questo, qualsiasi aiuto?

module Test where 

while :: (a -> Bool) -> (a -> IO a) -> a -> IO a 
while praed funktion x = do 
         f <- praed (funktion x) 
         if f == True then do 
              y <- funktion x 
              while praed funktion y 
         else return x 



power2 :: IO() 
power2 = do putStr (Please enter a number.") 
      i <- getChar 
      while praed funktion 
      where praed x = if x /= ' ' then False else True 
        funktion = i 
+3

Quindi, qual è la vostra domanda? Dove sei bloccato, cosa non funziona? – leftaroundabout

+0

Entrambe queste funzioni non sono ancora state compilate, e sono abbastanza sicuro che non farebbero quello che voglio che facciano comunque. Non so come scriverlo in una versione funzionante. Fondamentalmente sto cercando di ottenere un ciclo temporale che funzioni con una condizione. Quindi, per esempio, 'dispari (quadrato 3)' dovrebbe verificare se il quadrato 3 è dispari, quindi utilizzare il risultato del quadrato 3 = 9 e fare 'mentre dispari (quadrato 9)' e così via e via. Tecnicamente non dovrebbe aver bisogno di una x, dovrebbe funzionare solo con 'while condition function' – Chris

risposta

11
import Control.Monad 

while :: (a -> Bool) -> (a -> IO a) -> a -> IO a 
while praed funktion x 
    | praed x = do 
     y <- funktion x 
     while praed funktion y 
    | otherwise = return x 


power2 :: IO() 
power2 = do 
    putStr "Please enter a number." 
    i <- getChar 
    let praed x = x /= ' ' 
    let f x = do 
     putChar x 
     getChar 
    while praed f '?' 
    return() 

Alcune note:

  • utilizzando if x then True else False è ridondante, è pari a poco x.
  • Analogamente if x == True ... è ridondante ed equivalente a if x ....
  • È necessario distinguere tra le azioni IO ei relativi risultati. Per esempio, se yo fare

    do 
        i <- getChar 
        ... 
    

    poi nel ... i rappresenta il risultato dell'azione, un personaggio, così i :: Char. Ma getChar :: IO Char è l'azione stessa. È possibile visualizzarlo come una ricetta che restituisce Char quando viene eseguita. Puoi passare la ricetta alle funzioni ecc., E viene eseguita solo se eseguita da qualche parte.

  • Il tuo while chiamato funktion due volte, che probabilmente non è quello che intendi: leggerebbe un carattere due volte, controlla il primo e restituisce il secondo. Ricorda, il tuo funktion è un'azione, quindi ogni volta che "invochi" l'azione (ad esempio utilizzando <- funktion ... nella notazione do), l'azione viene eseguita nuovamente. Così dovrebbe invece essere qualcosa come

    do 
        y <- funktion x 
        f <- praed y 
        -- ... 
    

    (il mio codice è un po 'diversa, controlla l'argomento che viene passato a esso.)

+0

Impressionante, grazie. Capisco come hai fatto power2, ha molto senso. Non sono ancora sicuro di cosa stia succedendo esattamente mentre, tho. A che punto esatto, controlla se la condizione è vera? – Chris

+0

@Chris Controlla se la condizione vale per il suo argomento di tipo 'a' prima di fare qualsiasi altra cosa, proprio come fanno le istruzioni' while' nei linguaggi funzionali. Questo viene fatto usando [guards] (http://learnyouahaskell.com/syntax-in-functions#guards-guards), che è spesso preferibile su 'if/then/else'. La linea '| praed x = do ... 'dice _se la condizione' praed x' è vera, procedi con ..._. La prossima riga '| altrimenti = ... 'copre tutti i casi di riposo (perché' altrimenti' è solo un sinonimo di 'True', quindi' altrimenti' è una condizione sempre soddisfatta). –

3

Per una versione pura:

{-# LANGUAGE BangPatterns #-} 

while :: (a -> Bool) -> (a -> a) -> a -> a 
while p f = go where go !x = if p x then go (f x) else x 

test1 :: Int 
test1 = while (< 1000) (* 2) 2 
-- test1 => 1024 

per monadico:

import Control.Monad 

whileM :: (Monad m, MonadPlus f) => (a -> m Bool) -> m a -> m (f a) 
whileM p f = go where 
    go = do 
    x <- f 
    r <- p x 
    if r then (return x `mplus`) `liftM` go else return mzero 

test2 :: IO [String] 
test2 = whileM (return . (/= "quit")) getLine 
-- *Main> test2 
-- quit 
-- [] 
-- *Main> test2 
-- 1 
-- 2 
-- 3 
-- quit 
-- ["1","2","3"] 

power2 :: IO (Maybe Char) 
power2 = whileM (return . (/= 'q')) getChar 
-- *Main> power2 
-- q 
-- Nothing 
-- *Main> power2 
-- 1 
-- 2 
-- 3 
-- q 
-- Just '\n' 

vedere al so:

http://hackage.haskell.org/package/monad-loops, http://hackage.haskell.org/package/loop-while, http://hackage.haskell.org/package/control-monad-loop.

http://www.haskellforall.com/2012/01/haskell-for-c-programmers-for-loops.html

+5

Un'altra versione pura) 'while p = until (not.p)' – wowofbob

Problemi correlati