Category: отзывы

Category was added automatically. Read all entries about "отзывы".

with Cat The Cat

Про unsafePerformIO. (работа над моими ошибками)

Как посчитать количество сравнений?

Реализация в лоб, подсказанная мной, всегда печатает 1

Вот код, куда я добавил работающие функции myCmp3 и get_val2 (и в main тоже кое-что добавил в самый конец):
import List
import Data.IORef
import System.IO.Unsafe

myCmp :: Int -> Int -> Ordering
myCmp x y  
    | x < y = GT
    | x == y = EQ
    | x > y = LT
    
{-# NOINLINE cmpCountRef #-}
cmpCountRef :: IORef Int
cmpCountRef = unsafePerformIO $ newIORef 0

anotherCmp :: a -> a
anotherCmp x = unsafePerformIO $ do
    c <- readIORef cmpCountRef
    writeIORef cmpCountRef (c+1)
    return x

myCmp2 :: Int -> Int -> Ordering    
myCmp2 = (anotherCmp $ myCmp)

myCmp3 :: Int -> Int -> Ordering    
myCmp3 a b = anotherCmp $ myCmp a b
    
get_val = unsafePerformIO $ do
    c <- readIORef cmpCountRef
    return c
    
get_val2 () = unsafePerformIO $ do
    c <- readIORef cmpCountRef
    return c
    
main :: IO()
main = do
    print (sortBy myCmp2 [1, 9, 2, 8, 3, 7, 4, 6, 5])
    print (myCmp2 1 9)
    print (myCmp2 9 1)
    print (get_val)

    print (sortBy myCmp3 [1, 9, 2, 8, 3, 7, 4, 6, 5])
    print (myCmp2 1 9)
    print (myCmp2 9 1)
    print (get_val2 ())

myCmp2 вычисляет константу-функцию и запоминает ее. Ну, и получается, что сравнение вызвано всего один раз, хотя, на самом деле, вызвано не сравнение, а... ну, скажем, вычисление указателя на функцию сравнения.

То же и с get_val.

Обе этих функции представляют собой CAF, constant applicative form. С помощью CAF можно запоминать результаты, это очень удобно. Но в данном случае они мешаются.

Что я и исправил в myCmp3 - теперь мы подсчитываем количество вычислений myCmp a b, что правильно, - и get_val2, которой передается незначащий аргумент, превращающий ее в функцию.

Еще надо упомянуть про прагму NOINLINE. Если cmpCountRef будет подставлена в разные выражения, то и результатом вычисления копий ее тела будут разные ссылки, и в одном месте мы получим ссылку на область памяти 1, в другом - на область памяти 2. get_val же может получить ссылку на область памяти 3. А нам надо, чтобы у всех ссылки были одинаковые, что означает обращение к одной версии cmpCountRef. Что означает запрет на подстановку, NOINLINE.

PS
Надо собраться с силами и решить-таки Ванину задачку.
with Cat The Cat

Дочитал тезис Армстронга до приложений и даже дальше.

Making reliable distributed systems in the presence of software errors.

Страница 192, глава 8: распределение функций с побочными эффектами не является функцией... забыл, как называется, у Армстронга "step function." Жалуется, что без форсирования правил кодирования невозможно точное следование правилам хорошего стиля написания программ. Читай - "хочется статической типизации с отдельными типами для программ с побочными эффектами, наподобие Clean или Haskell."

Страница 219, приложении B: библиотечные функции с побочными эффектами мешают повторному использованию кода. Multiparadigm programming is a no-no! ;)

Ну, и ещё понемножку.

Например, разработка приложения ведётся с учётом возможности апгрейда с любой предыдущей версии (и даунгрейда в любую предыдущую версию, стр. 190). Не думаю, что это ускоряет разработку. Автоматические решения для апгрейда, как минимум, есть.

В общем, необходим "ящык программирования лучше, чем Erlang." ;)

А лучшее, как известно, враг хорошего (языка Ерланга). ;)