59
ЛЕНИВЫЕ ВЫЧИСЛЕНИЯ: плюсы и минусы (RuHaskell.Meetup 2015 Summer, fromGregorian 2015 06 21)

Ленивые вычисления: плюсы и минусы. Денис Шевченко

  • Upload
    -

  • View
    500

  • Download
    5

Embed Size (px)

Citation preview

Page 1: Ленивые вычисления: плюсы и минусы. Денис Шевченко

ЛЕНИВЫЕ

ВЫЧИСЛЕНИЯ:плюсы и минусы

(RuHaskell.Meetup 2015 Summer, fromGregorian 2015 06 21)

Page 2: Ленивые вычисления: плюсы и минусы. Денис Шевченко

  Лучше ничем не заниматься,чем заниматься ничем.

Ď

Тацит

Page 3: Ленивые вычисления: плюсы и минусы. Денис Шевченко

QUI EST QUI

Ħ

Page 4: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Haskell-программа —

совокупность выражений

/англ. expression/

Page 5: Ленивые вычисления: плюсы и минусы. Денис Шевченко

12.3 - 1.09

Это выражение

Page 6: Ленивые вычисления: плюсы и минусы. Денис Шевченко

"/home/dsh" </> "meetup2015"

И это

Page 7: Ленивые вычисления: плюсы и минусы. Денис Шевченко

head [15, 2, 6]

И это

Page 8: Ленивые вычисления: плюсы и минусы. Денис Шевченко

9

И даже это!

Page 9: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Запуск Haskell-программы —

начало вычисления её выражений

/англ. evaluation/

Page 10: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Вычислить выражение —

значит сократить его

/англ. reduce/

Page 11: Ленивые вычисления: плюсы и минусы. Денис Шевченко

В основе сокращения —

применение функции

/англ. function application/

Page 12: Ленивые вычисления: плюсы и минусы. Денис Шевченко

let sum = 2 + 3

Можно сократить

Page 13: Ленивые вычисления: плюсы и минусы. Денис Шевченко

let sum = (+) 2 3

Сокращаем…

Page 14: Ленивые вычисления: плюсы и минусы. Денис Шевченко

let sum = 5

Готово

Page 15: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Если сократить нельзя —

выражение в нормальной форме

/англ. normal form/

Page 16: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Если сократить можно —

выражение называют сокращаемым

/англ. reducible expression или redex/

Page 17: Ленивые вычисления: плюсы и минусы. Денис Шевченко

ПРИНЦИПЫ ЛЕНИ

ȣ

Page 18: Ленивые вычисления: плюсы и минусы. Денис Шевченко

№ 1ȣ

Выражение не сокращается,пока в этом нет необходимости

Page 19: Ленивые вычисления: плюсы и минусы. Денис Шевченко

main :: IO ()

main =

let stupid = 2 `div` 0

in print stupid

Вполне ожидаемая ошибка

Page 20: Ленивые вычисления: плюсы и минусы. Денис Шевченко

main :: IO ()

main =

let stupid = 2 `div` 0

in putStrLn "Just exit!"

Никакой ошибки

Page 21: Ленивые вычисления: плюсы и минусы. Денис Шевченко

№ 2ȣ

Спускаемся настолько,насколько это нужно

Page 22: Ленивые вычисления: плюсы и минусы. Денис Шевченко

main :: IO ()

main =

let some = ( 2 `div` 0

, [2 * 3, 4 `div` 0]

)

(_, second) = some

[elem1, _] = second

in print elem1

Ленивый лифт

Page 23: Ленивые вычисления: плюсы и минусы. Денис Шевченко

ПЛЮСЫ

Page 24: Ленивые вычисления: плюсы и минусы. Денис Шевченко

№ 1�

Рациональность

Page 25: Ленивые вычисления: плюсы и минусы. Денис Шевченко

main :: IO ()

main = do

file <- readFile "/home/dsh/big.log"

putStrLn $ take 100 file

Читаем лишь то, что нужно

Page 26: Ленивые вычисления: плюсы и минусы. Денис Шевченко

№ 2�

Бесконечность

Page 27: Ленивые вычисления: плюсы и минусы. Денис Шевченко

head :: [a] -> ahead (x:_) = x

Возвращаем первый элемент списка

Page 28: Ленивые вычисления: плюсы и минусы. Денис Шевченко

main :: IO ()

main =

print $ head [1, 10, 100]

Причём как конечного списка…

Page 29: Ленивые вычисления: плюсы и минусы. Денис Шевченко

main :: IO ()

main =

print $ head [1..]

… так и бесконечного

Page 30: Ленивые вычисления: плюсы и минусы. Денис Шевченко

№ 3�

DSL

Page 31: Ленивые вычисления: плюсы и минусы. Денис Шевченко

selectBy :: Bool -> (a, a) -> aselectBy True (f, _) = fselectBy False (_, s) = s

Замена условной конструкции

Page 32: Ленивые вычисления: плюсы и минусы. Денис Шевченко

import System.Exit

main :: IO ()

main = do

putStrLn "Input web prefix:"

prefix <- getLine

selectBy (prefix == "https")

( putStrLn "secure web :)"

, exitWith $ ExitFailure 1

)

И это честная замена!

Page 33: Ленивые вычисления: плюсы и минусы. Денис Шевченко

МИНУСЫ

Page 34: Ленивые вычисления: плюсы и минусы. Денис Шевченко

№ 1�

Неожиданное поведение

Page 35: Ленивые вычисления: плюсы и минусы. Денис Шевченко

import Data.String.Utils

main :: IO ()

main = do

file <- readFile path

writeFile path $ replace "," ";" file

where path = "/home/dsh/data"

Ну-ну…

Page 36: Ленивые вычисления: плюсы и минусы. Денис Шевченко

openFile: resource busy (file is locked)

Лень мешает

Page 37: Ленивые вычисления: плюсы и минусы. Денис Шевченко

import Data.String.Utils

import qualified System.IO.Strict as S

main :: IO ()

main = do

file <- S.readFile path

writeFile path $ replace "," ";" file

where path = "/home/dsh/data"

Строгость решает

Page 38: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Выход:

Не игнорируйте слова

strictly и lazily

в документации

Page 39: Ленивые вычисления: плюсы и минусы. Денис Шевченко

№ 2�

Space Leak

Page 40: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Не путать с Memory Leak!

Page 41: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Memory Leak —

низкоуровневая ошибкауправления памятью

Page 42: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Space Leak —

высокоуровневая ошибкапроектирования

Ǘ

Page 43: Ленивые вычисления: плюсы и минусы. Денис Шевченко

main :: IO ()

main =

let stupid = 2 `div` 0

in putStrLn "Just exit!"

Деления не было

Page 44: Ленивые вычисления: плюсы и минусы. Денис Шевченко

2 `div` 0

Невычисленное (отложенное) выражение

/англ. unevaluated expression или thunk/

Page 45: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Все отложенные выражения

живут в памяти

Thank you Cap!

Page 46: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Проблема в их количестве!

DZ

Page 47: Ленивые вычисления: плюсы и минусы. Денис Шевченко

f :: Num b => [a] -> b -> bf [] c = cf (_:xs) c = f xs $ c + 1

Пустышка с большой проблемой

Page 48: Ленивые вычисления: плюсы и минусы. Денис Шевченко

f [1,2,3] 0

Применяем…

Page 49: Ленивые вычисления: плюсы и минусы. Денис Шевченко

f 1:[2,3] 0 + 1

Первый шаг…

Page 50: Ленивые вычисления: плюсы и минусы. Денис Шевченко

f 1:2:[3] (0 + 1) + 1

Второй шаг…

Page 51: Ленивые вычисления: плюсы и минусы. Денис Шевченко

f 1:2:3:[] ((0 + 1) + 1) + 1

Третий шаг…

Page 52: Ленивые вычисления: плюсы и минусы. Денис Шевченко

f [] ((0 + 1) + 1) + 1

Последний шаг…

Page 53: Ленивые вычисления: плюсы и минусы. Денис Шевченко

((0 + 1) + 1) + 1 = 3

Готово

Page 54: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Ленивый вариант

main :: IO ()

main =

let v = f [1..50000000] (0 :: Integer)

in print v

Время: 62 с

Память: 6.19 ГБ

2

ǯ

Page 55: Ленивые вычисления: плюсы и минусы. Денис Шевченко

f' :: Num b => [a] -> b -> bf' [] c = cf' (_:xs) c = f' xs $! c + 1

Пустышка без проблем

Page 56: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Строгий вариант

main :: IO ()

main =

let v = f' [1..50000000] (0 :: Integer)

in print v

Время: 4 с

Память: мизерная

2

ǯ

Page 57: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Выход:

Если код может раздуться,разбавьте лень строгостью

Page 58: Ленивые вычисления: плюсы и минусы. Денис Шевченко

main :: IO ()

main =

print $ Laziness good bad

where good = [ "Рациональность"

, "Бесконечность"

, "DSL"

]

bad = [ "Неожиданное поведение"

, "Space Leak"

]

Page 59: Ленивые вычисления: плюсы и минусы. Денис Шевченко

Благодарю за внимание!

Денис Шевченко

dshevchenko.biz¢