Это экскурс по Michail 's и user2297560' s ответы.
Что делать, если вместо того, чтобы переписывать функцию с нуля, чтобы добавить функцию отслеживания, мы можем каким-то образом использовать оригинальную реализацию и «инструмент»?
Мы могли бы написать базовую функцию, которая
- Is монадическая, но полиморфный на монады.
- Определяется с помощью анонимной рекурсии с помощью
fix
.
Например:
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)
И тогда инструмент это, как это, повторное использование оригинального логика:
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
Но возможно определение функции, как «монадическая по умолчанию» не слишком практично ,
Это не самая удобная вещь, но вы можете изменить свою функцию, чтобы принять дополнительный аргумент, в котором вы будете хранить текущую глубину рекурсии, и вернуть tuple '(actualResult, finalRecursionDepth)'. – Michail
Это на самом деле то, что мне нужно. не могли бы вы уточнить. @Michail –
Я написал ответ. Он слишком велик, чтобы помещать его в комментарий (даже если это позволяет максимальная длина комментария). – Michail