Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
(Читать это определение стоит так: Bool может быть или True или False.) В принципе, можно было бы описать этот тип и в C++:
enum bool { true, false };
enum bool {
false,
true
};
строгая типизация накладывает слишком много нагрузки на программиста. … только вот есть технология, вывод типов, которая позволяет компилятору вывести большинство типов из контекста …
Или преуменьшает полезной динамическойА в чем эта полезность состоит, кроме очевидного факта, что меньше писать не надо? У меня маленький опыт работы с динамически типизированными языками, но я часто видел, как на таких языках, например, перед определением функции в комментариях пишут типы её аргументов (скажем, аргумент с таким именем должен быть строкой, а с таким — числом) или первыми строками в теле функции проверяют, что аргументы того типа, что надо.
В языках программирования функции, которые всегда дают одинаковый результат на одинаковых аргументах и не имеют побочных эффектов, называются чистыми.Отсюда напрямую следует, что чистая функция без аргументов обязана всегда возвращать один и тот же результат. Так что вы либо используете какое-то другое определение чистоты, либо не правы с точки зрения этого определения.
getRandomInt :: IO Int
(getRandomInt >>= \x -> return (toFloat x)) :: IO Float.
(getRandomInt >>= (\x -> getRandomInt >>= (\y -> return (x + y)))) :: IO Int
ghci> replicateM 3 (putStrLn "Hello")
Hello
Hello
Hello
[(),(),()]
ghci> execState (replicateM 3 (modify (+1))) 0
3
ghci> replicateM 3 [1,2]
[[1,1,1],[1,1,2],[1,2,1],[1,2,2],[2,1,1],[2,1,2],[2,2,1],[2,2,2]]
type IO a = RealWorld -> (a, RealWorld)
getChar :: RealWorld -> (Char, RealWorld)
main :: RealWorld -> ((), RealWorld)
main world0 = let (a, world1) = getChar world0
(b, world2) = getChar world1
in ((), world2)
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
return :: a -> m a --
(>>=) :: m a -> (a -> m b) -> m b
//чистая функция
function random(state) {
//[значение, новое состояние]
return [state % 10, state + 1];
}
//обычная функция
function add4(v) {
return v + 4;
}
//fs - чистая функция наподобии random, state - начальное состояние
function makeMonad(fs, state) {
//функция не принимающая состояние, помещенная в "коробку"
return function () {
return fs(state);
};
}
//fs - функция наподобии random, f - обычная функция не принимающая состояние, наподобие add4
//возвращается функция, обернутая в монаду c другим состоянием.
function bind(fs, f) {
return function() {
var [value, state] = fs();
return [f(value), state];
};
}
//получить чистое значение из монады, без изменения состояния
function call(fs) {
return fs[0];
}
//тогда пример работы с генератором:
var generator = makeMonad(random, 0);
bind(generator, function(randomValue) {
//здесь работаем с псевдослучайным значением
});
//чистая функция
function random(state) {
//[значение, новое состояние]
return [state + 1, state % 10];
}
function runMonad(mval, state) {
return mval(state);
}
function makeMonad(val) {
return function(state) {
return [val, state];
}
}
function bind(mval, fn) {
return function(state) {
var [val, state1] = mval(state);
return runMonad(fn(val), state1);
}
}
[sum, _] = runMonad(
bind(random, function(x) { // x is a first random number (16)
return bind(random, function(y) { // y is a second random number (6)
return makeMonad(x+y); // sum of two random numbers (22)
});
}),
15 // random seed
);
// sum == 22
data IO a = State a RealWorld
Ну, как я понимаю, здесь Bool — это алгебраический тип данных, или тип-сумма, или перечисление типов. То есть, объекты типа Bool могут принимать значения только перечисленных в нем типов (либо True, либо False). А у этих типов в свою очередь может быть только одно значение у каждого, которое конструируется просто вызовом True или False — в таком случае эти имена будут выступать как конструкторы значений своих типов.
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
Некорректная же программа не выдаст результата, а выдаст _|_ — на этом можно закончить анализ этого значения с точки зрения программиста.
fact =λx. x == 0 ? 1 : x * fact(x-1)fact. Для решения этих уравнений применяется оператор фиксированной точки. Применяется он к генерирующей функции, построенной по исходному выражению. В данном случае это будет простоgen = λfact. λx. x == 0 ? 1 : x * fact(x-1)gen^n(⊥) при n идущем в бесконечность (крышка обозначает степень). Можно доказать, что для монотонных функций в верхних полурешётках этот предел всегда существует.Так вот, гомотопии — это очень удобный инструментарий работы с АТД в Хаскеле.
Типизированные lambda-выражения это самый примитивный Тьюринг-полный из возможных языков.
mfilter :: (MonadPlus m) => (a -> Bool) -> m a -> m a
mfilter p ma = do
a <- ma
if p a then return a else mzero
type Lens' a b = forall f . (Functor f) => (b -> f b) -> (a -> f a)
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z [] = z
foldr k z (y:ys) = y `k` foldr k z ys
foldr1 :: (a -> a -> a) -> [a] -> a
foldr1 f (x:xs) = foldr f (f x) xs
foldr1 _ [] = errorEmptyList "foldr1"
fold :: (Foldable t, Monoid m) => t m -> m
fold :: (Foldable t, Monoid m) => t m -> m
fold = foldMap id
foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
foldMap f = foldr (mappend . f) mempty
Но тогда возникнет вопрос, а чем это всё [моноиды] будет полезнее для практики?
Возьмём, например, функцию свёртки:
("ABC" @ "DEF") @ "HIJ" ?== "ABC" @ ("DEF" @ "HIJ")
"ABC" @ "" ?== "ABC"
"" @ "ABC" ?== "ABC"
([1,2,3] ++ [4,5,6]) ++ [7,8,9] ?== [1,2,3] ++ ([4,5,6] ++ [7,8,9])
[1,2,3] ++ [] ?== [1,2,3]
[] ++ [1,2,3] ?== [1,2,3]
instance Monoid String where
mempty = ""
mconcat = (@)
instance Monoid [a] where
mempty = []
mconcat = (++)
("ABC" `mconcat` "DEF") `mconcat` "HIJ" ===
"ABC" `mconcat` ("DEF" `mconcat` "HIJ")
"ABC" `mconcat` mempty === "ABC"
mempty `mconcat` "ABC" === "ABC"
([1,2,3] `mconcat` [4,5,6]) `mconcat` [7,8,9] ===
[1,2,3] `mconcat` ([4,5,6] `mconcat` [7,8,9])
[1,2,3] `mconcat` mempty ?== [1,2,3]
mempty `mconcat` [1,2,3] ?== [1,2,3]
Чистая функция, которая возвращает блок
О, я просто напишу несколько строк кода и посмотрю, что происходитИменно так зачастую и бывает. Особенно, если в программе ошибка, а где именно — непонятно.
function fact(n) { return gmp_fact(n) }
Типы и функции