2015-03-11 2 views
1

Скажем, у меня есть функция concat :: String -> String -> String. Так,Haskell подсчет числа вызовов функции

var :: String 
var = concat (concat "a" "b") "c") -- "abc" 

Теперь у меня есть функция, которую я хочу использовать для расчета, сколько раз CONCAT называется:

func :: (String->String->String) -> Int 

Итак, func var должен вернуться 2.

Как я должен получить это значение и в то же время выполнить concat?

+2

Мне любопытно - почему вы хотите это сделать? –

ответ

6

Отложить это var. Неверный тип, вы не можете.

Причина 1: Вы можете написать точно такую ​​же функцию, как var, не звонив по телефону concat. Если предположить, что очевидное определение concat:

var1 = "a" ++ "b" ++ "c" 

или

var2 = "abc" 

В самом деле, компилятор превратит ваш var в var2 при компиляции с оптимизацией!

Причина 2: Что делать, если количество вызовов concat зависит от аргументов? Что должно быть

func f 
    where f x y = if x == "" then y else (concat x y) 

возвращение?

+0

Что делать, если тип String становится настраиваемым? – xcoder

+0

Это не имело бы никакого значения. –

+1

@xcoder Вы можете сделать это с помощью настраиваемого типа, который * хранит * функцию 'concat' и строковые аргументы, вместо фактического применения concat. Затем вы можете подсчитать количество конкатов в этой структуре данных и отдельно также запросить строку, которая будет создаваться путем фактического применения concat. Это в основном ответ @ dfeur. Но, не делая специальных аранжировок впереди, нет никакого способа рассказать, какие операции использовались, чтобы придумать заданное значение (типа * любого *). – Ben

6

Правильный способ для этого состоит в том, чтобы заменить concat :: String -> String -> String на concatA :: String -> String -> f (String), для некоторых подходящих Applicativef. Например, вы могли бы использовать Writer:

concatW :: String -> String -> Writer Int String 
concatW s1 s2 = Writer (s1++s2, Sum 1) 

Теперь

concatW s1 s2 >>= concatW s3 >>= concatW s4 

Или

(<=) <$> concatW s1 s2 <*> concatW s3 s4 

будет считать вещи для вас.


Если вы заинтересованы в том, сколько раз вызывается ваша функция для отладки, вы можете использовать trace из Debug.Trace. Вы также можете использовать профилировщик и аннотировать функцию как МВЗ. Вы даже можете использовать unsafePerformIO, если вы сумасшедший. Но это не то, что обычно должно появляться в выпущенной программе.