7

Desidero verificare le condizioni del precedente if condition per determinare se il prossimo if condition deve essere eseguito o meno. Ogni if condition può restituire un valore.Come semplificare nidificato-se si utilizza per restituire il valore in Haskell

Edit: Ci scusiamo per che l'esempio che ho fornito prima di guardare un po 'strano ... :( Questo è il mio vero esempio, e voglio semplificare il if-then-else per goingToMove

goingToMove p routes points w h = 
         if canMove p points 
          -- the point can be moved in the map 
          then let r = routes ++ [p] 
            l = remainList p points 
           in move p r l w h 
          -- the point cannot be moved in the maps 
          else [] 

move p routes points w h = 
      if (length routes) == 2 
       then routes 
       else let one = goingToMove (tallRightCorner p) routes points w h in 
        if (null one) 
         then let two = goingToMove(tallRightBCorner p) routes points w h in 
          if (null two) 
           then let three = goingToMove (tallLeftBCorner p) routes points w h in 
            if (null three) 
             then .... 
             ...... -- until, let eight = .. 
             else three 
           else two 
         else one 

Edit: cattivo esempio Quando questa cosa è scritto in Java, che può utilizzare un flag booleano mutevole, e restituire un dato mutabili.

public String move (int number){ 
     // base case 
     if (number == 0){ 
      return "Finished the recursion"; 
     } 
     // general case 
     else { 
      String result; 
      boolean isNull = false; 

      if ((result = move(3)) == null){ 
       isNull = true; 
      } 
      else { 
       return result; 
      } 

      // continue to execute the if-conditions if the previous condition failed 
      if (isNull){ 
       if((result = move(2)) == null){ 
        isNull = true; 
       } 
       else { 
        return result; 
       } 
      } 

      if (isNull){ 
       if((result = move(1)) == null){ 
        isNull = true; 
       } 
       else { 
        return result; 
       } 
      } 

      return null; 
     } 
    } 

Ma in Haskell, non ci sono dati mutabili e solo la condizione if-then-else. Poi il codice sarà simile a questo, e voglio semplificare questo perché nel mio vero lavoro, ci sono 8 livelli di if-then-else che sembrano terribile e disordinato ....

move 0 = "Finished the recursion" 
move n = 
    let one = move 3 in 
    if null one 
     then let two = move 2 in 
      if null two 
       then let three = move 1 in 
         then null 
         else three 
       else two 
     else one 
+0

Il 'move' che stai chiamando nel tuo codice Java è lo stesso del' move' che stai definendo? Se è così, non vedo come non si elimini all'infinito per un input diverso da zero. 'move (3)' chiama 'move (3)' chiama 'move (3)' ... – rampion

+0

Anche il codice haskell che hai fornito ha il tipo sbagliato. A un certo punto nel codice java stai restituendo "null", il che significa che il codice haskell dovrebbe essere "Int -> Forse String", anche se non era un ciclo infinito. Oh, e il codice haskell che suggerisci ha anche un errore di sintassi (manca una riga con un if in esso?) Che rende difficile capire esattamente cosa stai facendo. – Carl

+0

Ho fornito un esempio reale :(mi dispiace – code4j

risposta

16

In Java se volevo fare quanto segue:

result = func1(arg); 
if (result == null){ 
    result = func2(arg); 
    if (result == null){ 
    result = func3(arg); 
    if (result == null){ 
     result = func4(arg); 
    } 
    } 
} 
return result; 

Quello che sto essenzialmente facendo è trovare il primo risultato da func1(args), func2(args), func3(args), func4(args) che restituisce non null.

In Haskell, mi piacerebbe a modello func1, func2, func3, e func4 come funzioni che hanno restituito un valore Maybe a, in modo che potessero tornare Nothing se non sono riusciti.

func1, func2, func3, func4 :: Int -> Maybe Result 

allora posso usare il <|> dell'operatore (da Control.Applicative), che ha la seguente definizione per Maybe a:

Nothing <|> x = x 
x  <|> _ = x 

così posso convertire il sopra Java per

func1 arg <|> func2 arg <|> func3 arg <|> func4 arg 

E a causa del miracolo della valutazione lazy, func2 arg viene valutato solo se func1 arg restituisce Nothing, come nell'esempio Java.

+0

sembra bello, non ha niente significa nulla? – code4j

+0

'Forse a' è un tipo di dati che ha due costruttori:' Nothing :: Maybe a' e 'Just :: a -> Forse a'. Può essere definito come' data Forse a = Nothing | Just a'. – rampion

+0

Beautiful. Mmmmmm – AndrewC

1

modificare: Ecco un po 'di codice per il nuovo esempio:

move p routes points w h 
    | length routes == 2 = routes 
    | otherwise = find (not . null) . map gtm [tallRightCorner, tallRightBCorner, tallLeftBCorner] 
    where gtm f = goingToMove (f p) routes points w h 

Si noti che questo restituisce un forse. È possibile utilizzare fromMaybe per inserire un caso predefinito.

Ecco il vecchio (ma typechecking) Codice dal primo esempio proposto

move 0 = "Finished the recursion" 
move n = concat . maybeToList . msum $ map move' [3,2,1] 
    where move' x = let mx = move x in if null mx then Nothing else Just mx 
+2

Questo non viene compilato (anche se il codice nella domanda non viene compilato, quindi ...) –

+0

whoops è quello che ottengo per essermi affidato al mio typechecker mentale. – sclv

+0

Ho fornito un esempio reale :(sorry – code4j

12

A parte il bel lavoro di <|> che rampion ha dato ed il simile suggestione di sclv, un altro modo comune è quello di utilizzare le guardie, e sfruttare la pigrizia,

move :: Int -> Maybe String 
move n 
    | n == 0  = Just "Finished the recursion" 
    | isJust move3 = move3 
    | isJust move2 = move2 
    | isJust move1 = move1 
    | otherwise = Nothing 
     where 
     move3 = move 3 
     move2 = move 2 
     move1 = move 1 

per pigrizia, move i (i = 3, 2, 1) è solo valutato se è necessario.

Nel caso specifico, move 3 <|> move 2 <|> move 1 è molto bello, ma nei casi in cui le condizioni richiedono valutare funzioni differenti con differenti tipi di ritorno, l'uso di guardie e attacchi pigri in una clausola where può essere la soluzione naturale per evitare imbarazzante nidificata if S.

+0

qual è il significato di 'Just' e' isJust' ????? – code4j

+1

'Just' è un costruttore di valori di' Maybe a'. Dal momento che si ritorna e si verifica la presenza di 'null' nel proprio Java, se la versione di Haskell restituisce un' Maybe String' è l'analogia corretta. 'isJust' (disponibile dal modulo' Data.Maybe') verifica se un valore 'Maybe a' è un' Just a' o 'Nothing', quindi' isJust move3' corrisponde a 'if ((result = move (3))! = null) '[capovolgere il tuo' se/else's]. –

1

Si desidera routes se la sua lunghezza è 2 o il primo risultato non nullo da una serie di applicazioni di goingToMove che variano a seconda della funzione d'angolo applicata a p.

move p routes points w h 
    | length routes == 2 = routes 
    | otherwise = head 
       $ filter (not . null) 
       $ map tryMove corners 
    where tryMove f = goingToMove (f p) routes points w h 
      corners = [ tallRightCorner 
        , tallRightBCorner 
        , tallLeftBCorner 
        -- et cetera 
        ] 
0

Un'opzione senza Forse potrebbe essere quella di aggiungere una bandiera per la ricorsione (nell'esempio qui sotto, si potrebbe chiamare la funzione con il flag impostato su uno):

mossa p rotte punti wh 1

move p routes points w h flag 
    | (length routes) == 2 = routes 
    | otherwise = 
     if null result then move p routes points w h (flag+1) 
     else result 
     where result = case flag of 
         1 -> goingToMove (tallRightCorner p) routes points w h 
         2 -> goingToMove (tallRightBCorner p) routes points w h 
         3 -> goingToMove (tallLeftBCorner p) routes points w h 
         --...etc. 
         _ -> [] 
Problemi correlati