Frage

Für kulturelle und intellektuelle Bereicherung, habe ich beschlossen, ein wenig Haskell zu lernen. Ich habe rel="noreferrer"> Hughes und ich versuche seinen Code in wahres Haskell zu übersetzen. Ich habe einige meiner Versuch unten angebracht (für die numerischen Teile des Papiers, das Alpha-Beta-Algorithmus ist noch interessanter, aber ich würde auch ein Spiel Auswerter von Grund auf neu schreiben müssen!).

An diesem Punkt ist es eher eine Übung gewesen in Haskell Syntax als alles andere. Ich habe schon einfache Dinge getan wie repeat in die native Haskell iterate zu übersetzen, ein paar Funktionen übersetzen, die eine Menge von Klammern verwendet Zusammensetzung zu funktionieren (sie mehr punktfrei in den Prozess zu machen), etc.

Aber mein Code funktioniert sicher, und ich frage mich, ob es ausreichend „Haskell-ish“ ist. Kann keine Experten gibt einige Hinweise geben, mich aus?

-- 4.1 Newton-Raphson square roots
next n x = (x + n/x)/2.0

-- -- this is "iterate::(a->a)->a->[a]"
-- repeat f a  = a : iterate f (f a)

within eps (a:b:rest) = 
  if abs(a-b) <= eps 
    then b
    else within eps (b:rest)

sqroot a0 eps n = within eps (iterate (next n) a0)

relative eps (a:b:rest) = 
  if abs(a-b) <= eps*abs(b)
    then b
    else relative eps (b:rest)

relativesqrt a0 eps n = relative eps (iterate (next n) a0)

-- 4.2 numerical differentiation

easydiff f x h = (f (x+h) - f x) / h

differentiate h0 f x = map (easydiff f x) (iterate (/2) h0)

-- diff1a h0 eps f x = within eps (differentiate h0 f x)
diff1 h0 eps f = within eps . differentiate h0 f 

elimerror n (a:b:rest) = (b*(2**n)-a)/(2**n-1) : elimerror n (b:rest)

-- need fromIntegral to make a non-integer out of the Int which comes out of round
order (a:b:c:rest) =  fromIntegral (round (logBase 2 ((a-c)/(b-c)-1)))

improve s = elimerror (order s) s 

--diff2a h0 eps f x = within eps (improve (differentiate h0 f x))
diff2 h0 eps f = within eps . improve . differentiate h0 f 

--super s = map second (iterate improve s) -- how can we make this point-free?
super :: (RealFrac t, Floating t) => [t] -> [t] 
           -- w/o this it wants to be [double]->[double]
super = map second . iterate improve

-- second (a:b:rest) = b
second = head . tail

diff3 h0 eps f = within eps . super . differentiate h0 f

-- 4.3 integration

easyintegrate f a b = (f a + f b)*(b-a)/2

-- addpair becomes (uncurry (+))

integrate f a b = integ f a b (f a) (f b) 

integ f a b fa fb = 
  (fa+fb)*(b-a)/2 : map (uncurry (+)) (zip (integ f a m fa fm) (integ f m b fm fb))
  where m = (a+b)/2 
        fm = f m 

-- test: following should be about pi
approxpi eps = within eps (improve (integrate (\x -> 4/(1+x*x)) 0 1))
superpi eps = within eps (super (integrate (\x -> 4/(1+x*x)) 0 1))

-- is there any way to keep track of the number of iterations? state monad, but seems like a lot of work...\

Keine korrekte Lösung

Andere Tipps

4.1 Newton-Raphson Quadratwurzeln

Diese beiden Linien

sqroot a0 eps n = within eps (iterate (next n) a0)
relativesqrt a0 eps n = relative eps (iterate (next n) a0)

sind fast identisch, so konnte man abstrakte Dinge einen Schritt weiter:

sqroot method a0 eps n = method eps (iterate (next n) a0)
relativesqrt = sqroot relative
withinsqrt   = sqroot within

4.2 Numerische Differenzierung

Ich sehe den Punkt nicht h0 als Argument an die differentiate Funktion als es ist nur der Ausgangspunkt für die 0 Begrenzungssequenz aufweist. (Das gleiche gilt nicht für a0 in dem Newton-Rhapson Fall, wo der Ausgangspunkt Rolle könnte).

Ich denke, es ist gleichermaßen geeignet ist, die Geschwindigkeit zu abstrakt über deren diese Grenze gegen Null geht:

differentiate rate f x = map (easydiff f x) (iterate rate 1)

Natürlich könnte man beides tun:

differentiate rate h0 f x = map (easydiff f x) (iterate rate h0)

In jedem Fall ist es eine ziemlich willkürliche Entscheidung.

4.2 Integration

Sie können mit

zipWith (+) (integ f a m fa fm) (integ f m b fm fb)

statt

map (uncurry (+)) (zip (integ f a m fa fm) (integ f m b fm fb))

, die ich denke, mehr lesbar ist.

Für within und relative würde ich bewachte Notation:

within eps (a:b:rest)
  | abs(a-b)<=eps = b
  | otherwise = within eps (b:rest)

Für second, könnten Sie !! 1 schreiben. Vor allem, dass letzte ist persönliche Präferenz, ich denke.

Sie sollten auch die Art Signaturen geben.

Bearbeiten : Wenn Sie in den Verschleierungs sind, versuchen Sie:

within :: (Ord a, Num a) => a -> [a] -> a
within eps l@(_:xs) = snd. head . filter ((<= eps) . fst) $ zip zs xs
   where
    zs = zipWith (\ a b -> abs (a-b)) l xs

(Typ geprüft, nicht getestet - und ich weiß nie, ob ich die Filter richtig zu machen, oder wenn er negiert werden;)

Roger Costello hat zwei Teile Zusammenfassung der John Hughes Papier geschrieben Übersetzung der ursprünglichen Miranda Code zu Haskell. Hier sind Teil einer und Teil zwei seiner Zuschreibung.

Also, das ist eine gerade über Übersetzung (dh versuchen, den Code zu halten, so ähnlich wie möglich suchen) oder ein eingebettetes (dh wie viele idiomatische kleine Änderungen an dem Code wie möglich machen, ohne dass die Beispiele härter zu verstehen , natürlich) ein?

Unter der Annahme, dass dieses „Projekt“ ist noch im Gang ......

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top