Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
fmap :: Functor f => (a -> b) -> f a -> f b
> (+) <$> (*2) <*> (+10) $ 3
19
fmap (+ 1) [1, 2, 3, 4]
> [2, 3, 4, 5]
fmap (+ 1) (Just 5)
> Just 6
instance Functor [] where
fmap = map
Суть в том что в функциональных язык код фокусируется на результате, а в императивных — на процессе.Это уже к вопросу декларативность/императивность.
(+) <$> (*2) <*> (+10) $ 3
То, что мы можем ввести классы объектов… Ну. Замечательно. Но что с того? Если я пишу, допустим, текстовый редактор, как это мне поможет?
Повторюсь: вот пишу я текстовый редактор, где мне могут пригодиться классы объектов?
Интересным был бы пример какой-нибудь такой: допустим, нам надо посчитать спектр матрицы, объекты помогут нам в этой задаче так-то и так-то. Ну, или не знаю… При перемножении больших чисел через преобразование Фурье. Ну, то есть, в задаче, где есть реальные проблемы со сложностью кода. Было бы неплохо показать, в каком месте объектный подход срабатывает лучше теории типов.
Эти математические теории помогли создать эти языковые концепции, но вы же можете научиться управлять самолетом, не изучая всю ту физику, которая помогла создать летательные аппараты? Конечно.Неудачный пример. Управление самолётом требует базового понимания аэродинамики. То потом можно внезапно удивиться перед смертью, почему набирая высоту оказался в плоском штопоре… Можно, например, сказать, что оно не требует, скажем, серьезного понимания сопромата.
foldr и foldl не было бы. Автоматического и бесплатного параллелизма тоже в функциональном программировании нет, ну, если не прибегать к старым, добрым низкоуровневым ухищрениям типа компиляции map в LLVM с последующей векторизацией. Сама же классическая структура вычисления map весьма далека от «параллельной».>>= и return — ещё тот адский ад) вычисления, в которых необходим threading какого-нибудь состояния. Но даже для монад совершенно не ясно, какой profit можно получить от рассуждения о них в терминах теории категорий. Это всё вполне себе укладывается в теорию типов и в классы типов.fmap. Примеров мне не хватает для осознания. Как я уже говорил, я читал книгу Real World Haskell, и там что-то никаких рассуждений в терминах именно теории категорий нет. Разве только сказано, что термин «монада» взят из этой теории.Ещё раз повторю свой тезис: способ мышления программиста зависит от предметной области, а не от языка программирования. Кроме того, была огромная движуха во времена становления GUI-интерфейсов на тему программирования в виде блок-схем и прочих визуальных концепций. Систем была разработана туёвая хуча, но не одна не пошла в промышленность. Потому что сложные программы в виде блок-схем нереально сложно разрабатывать.Не совсем так. То же самое FBD нашло свою нишу в промышленной автоматике за счёт довольно низкого порога вхождения и кажущейся простоты (хотя там ещё активно используются схемы релейной автоматики/ladder diagrams и нечто похожее на классические блок-схемы).
newtype Identity a = Identity { runIdentity :: a }
instance Monad Identity where
return a = Identity a
m >>= k = k (runIdentity m)
type State s = StateT s Identity
IO будет написана на Си и всё сведётся к обращениям к операционной системе, которая даже чисто теоретически не может быть «функциональной».data MyText = MyText { .... }
instance Show MyText where
show t = ....
save :: FileName -> MyText -> IO ()
save f t = saveFile f (show t)
class MyText
{
....
public function save() { .... }
}
intersect_list :: Eq a => [a] -> [a] -> [a]
show и save. Или особенностью является то, что можно всё писать не в одном месте, а по мере необходимости? Так то же самое есть в JavaScript или Go. Тут, видимо, для осознания мной особенностей КТ-подхода, нужно понять, что такое «подключить категорию».instance и определить функции для этого интерфейса?-- library1.hs
data Natural = ...
-- library2.hs
data Negative = ...
-- library3.hs
class ToInteger a where
to_int :: a -> Integer
-- library4.hs
instance ToInteger Natural where
to_int :: Natural -> Integer
to_int = fromNatural
-- library5.hs
instance ToInteger Negative where
to_int :: Negative -> Integer
to_int = multiply (-1) . fromNegative
-- app.hs
any_add :: ToInteger a => a -> a -> Integer
any_add x y = ineger_add (to_int x) (to_int y)
class Natural {
...
function type() {..}
function add_nat (Natural $b) { ... }
function add_neg (Negative $b) { ... }
function add_any ($b) {if ($b->type() == "Natural") return $this->add_nat($b);...}
}
class Negative {
...
function type() {..}
function add_nat (Natural $b) { ... }
function add_neg (Negative $b) { ... }
function add_any ($b) {if ($b->type() == "Natural") return $this->add_nat($b);...}
}
class Integer {
...
function type() {..}
function add_any ($b) {...}
}
trait Type {
type () { ... }
}
trait AddAny {
add_any($b) { ...}
}
class Natural extends Type, AddAny {
...
function type() {..}
function add_nat (Natural $b) { ... }
function add_neg (Negative $b) { ... }
function add_any ($b) {if ($b->type() == "Natural") return $this->add_nat($b);...}
}
class Negative extends Type, AddAny {
...
function type() {..}
function add_nat (Natural $b) { ... }
function add_neg (Negative $b) { ... }
function add_any ($b) {if ($b->type() == "Natural") return $this->add_nat($b);...}
}
class Integer extends Type, AddAny {
...
function type() {..}
function add_any ($b) {...}
}
(.) :: (b -> c) -> (a -> b) -> a -> c
to_int = multiply (-1) . fromNegative
class Category cat where
id :: cat a a
(.) :: cat b c -> cat a b -> cat a c
getLine :: IO String
fromIO :: IO a -> a
f <=< return == f
return <=< f == f
f <=< (g <=< h) == (f <=< g) <=< h
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f >=> g = \x -> f x >>= g
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
(<=<) = flip (>=>)
inet_addr :: String -> IO HostAddress
wr some-pci-address, some-value. Проблема заключается в повторных записях/чтениях по одному и тому же адресу.IO. И, видимо, прямую адресацию памяти в Си можно трактовать точно так же. Но возникает вопрос о прерываниях, о многопроцессорных системах.IO, написанная неким внешним способом. IO можно будет переписать на этом ассемблере и замкнуть круг?IO, у нас будет компилятор Haskell, который будет генерировать программы, которые будут генерировать ассемблер для IO. Язык один, но есть такой вот дополнительный шаг. Какой-то есть в этом всём намёк на неподвижные точки, IMHO.IO?unsafe и мы сами виноваты. Но вот проблема в том, что в рамках теории процессов, мы можем отказаться от необходимости таких произвольных доступов. У нас просто будет процесс, который отвечает за своё устройство. И нам нет никакой необходимости заниматься чем-то небезопасным. Ну, видимо, в Haskell мы можем напорождать кучу монад для разных устройств… Эх. Только вот программирование будет потом каким-то адским адом из lift-ов. Но… В принципе, это IO и обычный пользователь не увидит.data Proxy a' a b' b m r
= Request a' (a -> Proxy a' a b' b m r )
| Respond b (b' -> Proxy a' a b' b m r )
| M (m (Proxy a' a b' b m r))
| Pure r
echo $((`cat file-1.txt | wc -l` + `cat file-2.txt | wc -l`))forkIO. А посоветуйте что-нибудь почитать именно об этом самом RealWorld. Мне никогда не попадалось на глаза.Как только вам нужно смотреть в реализации объекта, чтобы понять, как компоновать его с другими объектами, вы потеряли достоинства ООП.
Но в математике и в функциях Haskell композиция направлена справа-налево.
(?) = flip (.)
f . g эквивалентно g ? f(&) = flip ($)
Кому-нибудь эта статья помогла?
Категория: суть композиции