questo è abbastanza semplice tradurre:
module PNormalDist where
pnormaldist :: (Ord a, Floating a) => a -> Either String a
pnormaldist qn
| qn < 0 || 1 < qn = Left "Error: qn must be in [0,1]"
| qn == 0.5 = Right 0.0
| otherwise = Right $
let w3 = negate . log $ 4 * qn * (1 - qn)
b = [ 1.570796288, 0.03706987906, -0.8364353589e-3,
-0.2250947176e-3, 0.6841218299e-5, 0.5824238515e-5,
-0.104527497e-5, 0.8360937017e-7, -0.3231081277e-8,
0.3657763036e-10, 0.6936233982e-12]
w1 = sum . zipWith (*) b $ iterate (*w3) 1
in (signum $ qn - 0.5) * sqrt (w1 * w3)
Prima di tutto, diamo un'occhiata al rubino - restituisce un valore, ma a volte un messaggio d'errore (quando dato un argomento improprio). Questo non è molto haskellish, quindi il nostro valore di ritorno è Either String a
- dove restituiremo un Left String
con un messaggio di errore se viene fornito un argomento errato e un Right a
altrimenti.
Ora controlliamo i due casi in alto:
qn < 0 || 1 < qn = Left "Error: qn must be in [0,1]"
- questa è la condizione di errore, quando qn
è fuori portata.
qn == 0.5 = Right 0.0
- questo è il controllo rubino qn == 0.5 and return * 0.0
Next up, definiamo w1
nel codice Ruby. Ma lo ridefiniamo poche righe dopo, che non è molto rubino. Il valore che memorizziamo nella per la prima volta è immediatamente utilizzato nella definizione di w3
, quindi perché non ignorare la memorizzazione in w1
? Non abbiamo nemmeno bisogno di fare il passo qn > 0.5 and w1 = 1.0 - w1
, perché usiamo il prodotto w1 * (1.0 - w1)
nella definizione di w3.
Quindi saltiamo tutto ciò e passiamo direttamente alla definizione w3 = negate . log $ 4 * qn * (1 - qn)
.
Il prossimo è la definizione di b
, che è un passaggio diretto dal codice rubino (la sintassi di ruby per un array letterale è la sintassi di haskell per un elenco).
Ecco il bit più difficile: definire il valore finale di w3
. Quello che il codice Ruby fa in
w1 = b[0]
1.upto 10 do |i|
w1 += b[i] * w3**i;
end
E 'quello che viene chiamato una piega - la riduzione di un insieme di valori (memorizzati in una matrice rubino) in un singolo valore. Siamo in grado di riformulare questa più funzionale (ma ancora in Ruby) utilizzando Array#reduce
:
w1 = b.zip(0..10).reduce(0) do |accum, (bval,i)|
accum + bval * w3^i
end
Nota come ho spinto b[0]
nel circuito, utilizzando l'identità b[0] == b[0] * w3^0
.
Ora potremmo porta questo direttamente a Haskell, ma è un po 'brutto
w1 = foldl 0 (\accum (bval,i) -> accum + bval * w3**i) $ zip b [0..10]
Invece, ho rotto in su in diverse fasi - prima di tutto, non abbiamo davvero bisogno i
, abbiamo solo bisogno di Potenze di w3
(a partire da w3^0 == 1
), quindi calcoliamo quelli con iterate (*w3) 1
.
Quindi, piuttosto che zippare quelli in coppie con gli elementi b, in definitiva abbiamo solo bisogno loro prodotti, in modo da poter comprimili in i prodotti di ciascuna coppia con zipWith (*) b
.
Ora la nostra funzione di piegatura è davvero semplice: abbiamo solo bisogno di riassumere i prodotti, cosa che possiamo fare usando sum
.
Infine, decidere se tornare più o meno sqrt (w1 * w3)
, a seconda che qn
è maggiore o minore di 0,5 (che già sappiamo che non è uguale). Quindi, piuttosto che calcolare la radice quadrata in due posizioni separate come nel codice rubino, l'ho calcolato una volta e lo ho moltiplicato per +1
o -1
in base al segno di qn - 0.5
(signum
just returns the sign of a value).
Non so davvero nulla delle statistiche: P. Sai quale di quelle funzioni è equivalente a un anonimo? –
Non credo che nessuna di queste funzioni sia esattamente ciò di cui hai bisogno. Hai bisogno dell'inverso della funzione erf, se non sbaglio. – augustss