a -> b
связывают с возведением в степень, \(b^a \sim a \to b\)()
– \(1\)Bool
– \(2\)f
– 0g
– 1h
– 4:
h = const True
h = const False
h = id
h = not
q
– \(\abs{\mathrm{Int}}\).Type
Type -> Type
и т.п.Constraint
– слева от =>
, т.е. Class a :: Constraint
, где Class
– класс типа с одним аргументом (расширение ConstraintKinds
)DataKinds
делает все пользовательские типы также и родамиdata MyBool = MyTrue | MyFalse
⇒ род MyBool
, населённый типами MyTrue
и MyFalse
'MyTrue
, чтобы разрешить неоднозначностьВстроенные типы:
String
⇒ Symbol
. Литералы строк не являются списками. Операции AppendSymbol
, CmpSymbol
Nat
. Операции +
, *
, ^
, -
, Div
, Mod
, Log2
и CmpNat
.[a]
, типы '[] :: [a]
и '(:) :: a -> [a] -> [a]
, где после ::
указан род, и a
– переменная рода.(a, b)
и т.п. Конструкторы типов рода кортежей соответственно '(,)
и т.п.'(,)
и '[]
кавычка обязательна (пересекается с конструкторами типов (,)
и[]
)GHC.TypeLits
Какие являются функторами?
data T1 a = T1 (Int -> a)
data T2 a = T2 (a -> Int)
data T3 a = T3 (a -> a)
data T4 a = T4 ((Int -> a) -> Int)
data T5 a = T5 ((a -> Int) -> Int)
Для ответа – понятие вариантности.
Виды вариантности:
a -> b
может быть единообразно преобразована к виду T a -> T b
Functor
. Functor
– ковариантный функтор.
a -> b
может быть единообразно преобразована к виду T b -> T a
a -> b
неможет быть единообразно преобразована к типам T a
, T b
Для контравариантных типов можно определить конртавариантный функтор
(из библиотеки contravariant
)
data T1 a = T1 (Int -> a)
instance Functor T1 where
fmap f (T1 x) = T1 (f . x)
data T2 a = T2 (a -> Int)
instance Contravariant T2 where
contramap f (T2 x) = T2 (x . f)
data T3 a = T3 (a -> a)
instance Invariant T3 where
invmap f g (T3 x) = T3 (f . x . g)
data T4 a = T4 ((Int -> a) -> Int)
instance Contravariant T4 where
contramap f (T4 x) = T4 (\g -> x (f . g))
data T5 a = T5 ((a -> Int) -> Int)
instance Functor T5 where
fmap f (T5 x) = T5 (\g -> x (g . f))
base
в модуле Data.Bifunctor
profunctors
.
MultiParamTypeClasses
.TypeFamilies
Map
)FunctionalDependencies
TypeFamilyDependencies
TypeApplications
@_
=>
TypeApplications
можно обойти это ограничениеAllowAmbiguousTypes
.До появления TypeApplications
использовался
Семейства типов и синонимы типов могут сделать некоторые типы неочевидно “неоднозначными” (ambiguous). Например,
a
находится справа от =>
someFunc :: Show a => () -> String
someFunc ()
не было бы никаких указаний на тип a
.type NotProxy a = ()
отличается от типа data Proxy a = Proxy
.Proxy a
изоморфен типу ()
data Proxy a
объявляет новый конструктор типа Proxy
NotProxy
не объявляет тип.Выражения слева от =>
имеют род Constraint
. Такие выражения могут быть:
Show a
Constraint
, например (Show a, Read a)
a ~ b
, где ~
– оператор эквивалентности.(~) :: k -> k -> Constraint
class (~) a b
, экземпляры только для случаев a = b
, например instance (~) Int Int
и т.п.~
позволяет говорить об эквивалентности типовТехнически, эти определения эквивалентны.
GADTs
data Expr a where
LitInt :: Int -> Expr Int
LitFloat :: Double -> Expr Double
Add :: (Expr Int) -> (Expr Int) -> (Expr Int)
FAdd :: (Expr Double)
-> (Expr Double)
-> (Expr Double)
GADTs
Эквивалентно:
data Expr a
= a ~ Int => LitInt Int
| a ~ Double => LitFloat Double
| a ~ Int => Add (Expr Int) (Expr Int)
| a ~ Double => FAdd (Expr Double) (Expr Double)
(требует ExistentialQuantification
)
RankNTypes
.a
должен определяться в месте вызова f
, и нет никаких причин полагать что a ~ Int
.Интересно отметить, что a
изоморфен forall r. (a -> r) -> r
forall r. (a -> r) -> r ≈ a ≈ Identity a
Identity a
- монадаforall r. (a -> r) -> r
– монадаПо сути, использование оператора >>=
без do-нотации использует CPS, передавая продолжение вторым аргументом >>=
.