Dies ist ein Exkurs über Michail 's und user2297560' s Antworten.
Was wäre, wenn wir, anstatt die Funktion von Grund auf neu zu schreiben, um Tracking-Funktionalität hinzuzufügen, könnten wir die ursprüngliche Implementierung und "Instrument" in irgendeiner Weise wiederverwenden?
Wir könnten eine Basisfunktion schreiben, die
- monadischen, aber polymorphen auf der Monade.
- Wird mithilfe der anonymen Rekursion mit Hilfe von
fix
definiert.
Zum Beispiel:
import Data.Function(fix)
import Data.Functor.Identity
maximumAux :: (Monad m,Ord a)
=> ([a] -> m a)
-> [a] -> m a
maximumAux _ [] = error "maximum of empty list"
maximumAux _ [x] = return x
maximumAux recurse (x:xs) =
do maxTail <- recurse xs
return (max x maxTail)
maximumPure :: Ord a => [a] -> a
maximumPure as = runIdentity (fix maximumAux as)
Und dann Instrument es so, die ursprüngliche Logik Wiederverwendung:
maximumInstrumented :: (Ord a, Show a) => [a] -> IO a
maximumInstrumented = fix (instrument maximumAux)
where
instrument auxf iorecurse as =
do print $ "starting call with params " ++ show as
a <- auxf iorecurse as
print $ "ending call with value" ++ show a
return a
Aber vielleicht funktioniert als "monadischen by default" definiert, ist nicht zu praktisch .
Es ist nicht die bequemste Sache, aber Sie könnten Ihre Funktion ändern, um ein zusätzliches Argument zu nehmen, in dem Sie die aktuelle Rekursionstiefe speichern und das Tupel '(actualResult, finalRecursionDepth)' zurückgeben. – Michail
Das ist eigentlich was ich brauche. Kannst du bitte etwas ausarbeiten? @Michail –
Ich habe eine Antwort geschrieben. Es ist ein bisschen zu groß, um es in einen Kommentar einzufügen (selbst wenn die maximale Kommentarlänge es erlaubt). – Michail