Реализуйте race :: IO a -> IO b -> IO (Either a b)
. Используйте forkIO
, throwTo
, MVar
.
Семантика: когда один из тредов завершился, другой убиваем и возвращаем результат (или кидаем exception если тред завершился с exception'ом). Будьте внимательны к обработке асинхронных exception'ов. В результате работы вашей функции не должно оставаться неубитых тредов.
Используйте функцию bracket
для того чтобы открыть файл и посчитать кол-во символов x
.
Implement parallel Monte-Carlo integral calculation.
Choose function to integrate yourself.
integrate
:: RandomGen g
=> g -- ^ Random generator
-> Int -- ^ Number of random points to generate
-> Double -- ^ Lower bound
-> Double -- ^ Upper bound
-> (Double -> Double) -- ^ Function to integrate
-> Double
In Monte-Carlo method we generate N
random points,
calculate function value at each point and then calculate mean value
multiplied by b - a
for b
and a
being upper and lower bounds respectively.
Account name is represented by String
.
Account balance is represented by Int
.
Ledger is a map from account name to balance, supporting following operations:
- Get current balance of account
A
- If there is no key
A
in the map, return0
- If there is no key
- Transfer
c
coins from accountA
to accountB
- If
A
has balance of less thanc
coins, throw an exception
- If
Implement a ledger as newtype over Map
from http://hackage.haskell.org/package/stm-containers-1.1.0.2/docs/StmContainers-Map.html.
Try to launch 100000 concurrent operations, working on:
- Same keys
- Different keys
And roughly compare performance via output of RTS (see slides).
В этом задании запрещается использовать библиотеки с линзами.
Настоящие линзы имеют следующий тип:
type Lens s t a b = forall f . Functor f => (a -> f b) -> s -> f t
Но для простоты мы будем использовать линзы Ван Лаарховена (или же «простые линзы»):
type Lens' s a = Lens s s a a
Реализуйте следующие базовые примитивы по работе с линзами:
set :: Lens' s a -> a -> s -> s -- set value (setter)
view :: Lens' s a -> s -> a -- lookup value (getter)
over :: Lens' s a -> (a -> a) -> s -> s -- change value (modifier)
Подсказка: используйте функторы Const
и Identity
для этого задания.
Можно использовать операторные формы этих функций:
(.~) :: Lens' s a -> a -> s -> s
(^.) :: s -> Lens' s a -> a
(%~) :: Lens' s a -> (a -> a) -> s -> s
После этого реализуйте простейшие линзы для пары (!!! реализуйте эти функции вручную, запрещается использовать lens
из усложнённой версии !!!):
-- _1 :: Functor f => (a -> f b) -> (a, x) -> f (b, x)
_1 :: Lens (a, x) (b, x) a b
_1 = _
-- _2 :: Functor f => (a -> f b) -> (x, a) -> f (x, b)
_2 :: Lens (x, a) (x, b) a b
_2 = _
Линза представляет собой по сути пару из геттера и сеттера. Следовательно, прежде чем использовать линзу, необходимо научиться создавать её. Для этого реализуйте следующую функцию:
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
lens get set = _
Подсказка: Если реализовать функцию выше тяжело, то попробуйте для начала реализовать более простую версию.
lens :: (s -> a) -> (s -> a -> s) -> Lens' s a
│ │
│ └─ setter
│
└── getter
После этого реализуйте линзы, которые сложней, чем _1
и _2
:
-- Объединить две линзы в одну, которая работает с Either.
choosing :: Lens s1 t1 a b
-> Lens s2 t2 a b
-> Lens (Either s1 s2) (Either t1 t2) a b
choosing l1 l2 = _
-- Изменить цель линзы и вернуть новый результат. Постарайтесь
-- реализовать без анонимных функций и определений своих функций
(<%~) :: Lens s t a b -> (a -> b) -> s -> (b, t)
(<%~) l f s = _
-- Изменить цель линзы, но вернуть старый результат.
(<<%~) :: Lens s t a b -> (a -> b) -> s -> (a, t)
(<<%~) l f s = _
Реализуйте свой аналог ST
монады, поддерживающий значения произвольного типа.
Код должен содержаться в отдельном модуле, модуль не должен экспортировать ничего что может позволить сломать инварианты ST монады.
Тип данных STRef
должен соответствовать переменной, существующей в контексте Вашей ST
монады.
В реализации можете использоватьTypeable
.
В отдельном модуле реализуйте примеры использования.
Данный пример должен компилироваться с Вашим кодом и вычислять i-е число Фибоначчи:
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib i = runST $ do
s <- newSTRef 0
t <- newSTRef 1
forM_ [2..i] $ \_ -> do
_s <- readSTRef s
_t <- readSTRef t
writeSTRef s _t
writeSTRef t (_s + _t)
readSTRef t
Следующий пример также должен компилироваться и вычислять квадратный корень числа с плавающей точкой.
eps :: Double
eps = 1.0e-15
whileM :: Monad m => m Bool -> m () -> m ()
whileM c act =
c >>= \b ->
if b
then act >> whileM c act
else pure ()
sqrt' :: Double -> Double
sqrt' x
| x < 1 = error "x < 1 not supported"
| x == 0 = 0
| otherwise = runST $ do
l <- newSTRef 0
r <- newSTRef x
let checkCond = do
l_ <- readSTRef l
r_ <- readSTRef r
pure (r_ - l_ > eps)
whileM checkCond $ do
l_ <- readSTRef l -- l^2 < x
r_ <- readSTRef r -- r^2 >= x
let m = (l_ + r_) / 2
if (m * m >= x)
then writeSTRef r m
else writeSTRef l m
readSTRef r