2011-09-10 19 views
23

Sto facendo una funzione in Haskell che dimezza solo le variabili in una lista e sto riscontrando un problema. Quando eseguo il compilatore si lamenta che non è possibile eseguire la divisione di un int e che ho bisogno di una dichiarazione di tipo int frazionale. Ho provato a cambiare la dichiarazione del tipo in float, ma questo ha generato solo un altro errore. Ho incluso il codice della funzione qui sotto e speravo in qualsiasi forma di aiuto.Divisione in Haskell

halfEvens :: [Int] -> [Int] 
halfEvens [] = [] 
halfEvens (x:xs) | odd x = halfEvens xs 
       | otherwise = x/2:halfEvens xs 

Grazie per la lettura.

+1

Penso che tu voglia x 'div' 2 in questo caso. Lascerò che qualcun altro confermi che ho ragione (non sono sicuro al 100%) e darò una spiegazione più completa. – MatrixFrog

risposta

31

Uso div, che svolge divisione intera:

halfEvens :: [Int] -> [Int] 
halfEvens [] = [] 
halfEvens (x:xs) | odd x = halfEvens xs 
       | otherwise = x `div` 2 : halfEvens xs 

La funzione (/) richiede argomenti cui tipo è rappresentato nella classe Fractional, ed esegue la divisione standard. La funzione div richiede argomenti il ​​cui tipo è nella classe Integral ed esegue la divisione integer.

Più precisamente, div e mod rotondo verso l'infinito negativo. I loro cugini, quot e rem, si comportano come integer division in C e arrotondano verso lo zero. div e mod di solito sono corretti quando si esegue l'aritmetica modulare (ad esempio quando si calcola il giorno della settimana in base a una data), mentre quot e rem sono leggermente più veloci (credo).

Giocando un po 'intorno a GHCi:

> :t div 
div :: Integral a => a -> a -> a 
> :t (/) 
(/) :: Fractional a => a -> a -> a 
> 3/5 
0.6 
> 3 `div` 5 
0 
> (-3) `div` 5 
-1 
> (-3) `quot` 5 
0 
> [x `mod` 3 | x <- [-10..10]] 
[2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1] 
> [x `rem` 3 | x <- [-10..10]] 
[-1,0,-2,-1,0,-2,-1,0,-2,-1,0,1,2,0,1,2,0,1,2,0,1] 
+0

Grazie mille per il vostro aiuto. – D347th

+0

Sì, quot è più veloce perché è quello che tende a fare l'istruzione della macchina. Tranne il processore NS32k che aveva entrambi i tipi di istruzioni di divisione. – augustss

+1

ghc ottimizza la divisione di una potenza di 2 in una svolta a destra? Uno spostamento aritmetico a destra di n bit dividerà per 2 ** n, ma arriverà verso l'infinito negativo (se si sposta a destra -1, si ottiene ancora -1). Per arrotondare verso 0, devi aggiungere (2 ** n) -1 se l'input è negativo prima dello spostamento. In questo caso, 'div' dovrebbe essere più veloce di' quot' – pat

0

Vorrei aggiungere che utilizzando map semplificherebbe il codice.

HalfIfEven n 
    | even n = n `div` 2 
    | otherwise = n 

halfEvens = map halfIfEven 
+0

Ma questo non ti dà lo stesso risultato. Il codice originale rimuove le probabilità, il tuo no. Il più semplice sarebbe probabilmente 'halfEvens = map (\' div \ '2). filtro uniforme' – semicolon