История изменений
Исправление quasimoto, (текущая версия) :
Сам я пишу на C++ и привык читать инстанцирование класса, как «ConcreteObject - это SomeClass». Как мне показалось, в haskell так делать нельзя.
То что в C++ называется классами и объектами в Haskell называется ADT и значениями (термами).
Например, такой код с классами, объектами и методами:
#include <cstdio>
struct a_t {
int x, y;
int sum() { return x + y; }
};
class ab_t {
// @tagged_union
enum { a_tag, b_tag } tag;
union {
a_t a;
struct {
int x, y, z;
int sum() { return x + y + z; }
} b;
} ab_u;
public:
ab_t(a_t a_) : tag(a_tag) { ab_u.a = a_; }
ab_t(int x_, int y_, int z_) : tag(b_tag) { ab_u.b = { x_, y_, z_ }; }
int sum() { return tag == a_tag ? ab_u.a.sum() : ab_u.b.sum(); }
};
int main()
{
ab_t ab1({1, 2});
ab_t ab2(3, 4, 5);
printf("ab1.sum = %d; ab2.sum = %d\n", ab1.sum(), ab2.sum());
}
В Haskell переводится в код с ADT, значениями и функциями:
import Text.Printf
data A = A Int Int
data AB = A_ A | B Int Int Int
a_ :: Int -> Int -> AB
a_ x y = A_ $ A x y
sumA :: A -> Int
sumA (A x y) = x + y
sumAB :: AB -> Int
sumAB (A_ a) = sumA a
sumAB (B x y z) = x + y + z
main :: IO ()
main = printf "sumAB a = %d; sumAB b = %d\n" (sumAB $ a_ 1 2) (sumAB $ B 3 4 5)
«объект класса» превращается в «терм/значение (алгебраического) типа».
Разница между классами и методами C++ и ADT и функциями Haskell в том, что в C++ может легко начаться наследование, подтипирование и динамическая диспетчеризация, тогда как в Haskell это делается не так легко.
Теперь, если применить в Haskell концепцию классов типов:
class Sum t where
sumt :: t -> Int
instance Sum A where
sumt (A x y) = x + y
instance Sum AB where
sumt (A_ a) = sumt a
sumt (B x y z) = x + y + z
main :: IO ()
main = printf "sum a = %d; sum b = %d\n" (sumt $ a_ 1 2) (sumt $ B 3 4 5)
то, наоборот, в С++ это уже не так легко. Классы типов не имеют отношения к классам С++, они имеют отношения к интерфейсам и концептам - первые в С++ довольно неудобны:
struct sum_i {
virtual ~sum_i() {}
virtual int sum() const = 0;
};
struct a_t : public sum_i {
int x, y;
a_t(int x_, int y_) : x(x_), y(y_) {}
int sum() const { return x + y; }
};
class ab_t : public sum_i {
// ?
};
а вторых ещё нет (про функторы на них можно посмотреть тут - http://www.pik-potsdam.de/members/lincke/papers/Lincke_et_al_SCP.pdf).
говорит о том что для типа [] определен функтор осуществляющий отображение стрелок над элементами списка в стрелки над списками
[] это и есть функтор - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.103.9637. Класс типов Functor это не функтор и не тип, если мы его интернализируем в язык, это будет класс. То есть если 5 :: Int :: * :: **, тогда Functor :: (* -> *) -> ** (Functor :: (* -> *) -> Constraint в нынешнем GHC, то есть оно там «constraint»).
В зависимости от того, каким функтором является ADT, можно про него сказать разные вещи, в том числе, является ли этот ADT хорошим, то есть не приведёт ли его существование к противоречиям в языке («строго-позитивные функторы»).
А сущность Functor это вещь (класс/constraint) которая нужна либо для того чтобы принять на веру что данный ADT это функтор, объявить функторный интерфейс и реализовать его для данного ADT, либо для того чтобы _доказать_ что данный ADT это функтор (ну и тоже - объявить функторный интерфейс и реализовать его для данного ADT).
«для типа Something инстанцирован/описан/реализован Functor», но не «Something - это Functor»?
Тип Something :: * -> * это функтор (с маленькой буквы и если это ещё функтор, конечно), что подтверждается существованием для этого типа инстанса класса типов (класса) Functor (с большой буквы), если в языке выразимы аксиомы функтора это будет буквальным подтверждением, то есть строгим доказательством того что Something - функтор.
Ну и почему в классе Functor описано отображение для стрелок, но не описано отображение для объектов (как pure из класса Applicative)?
Отображением стрелок/значений/конструкторов/термов/функций/программ занимается стрелка/функция/программа fmap :: (a -> b) -> (f a -> f b) в рантайме, отображением объектов/типов занимается функтор/конструктор типов f :: * -> * во время компиляции. Все Functor, Pointed, Applicative, Monad описывают, на самом деле, только эндофункторы только одной категории Hask - категории всех типов и термов/конструкторов/классов эквивалентности функций-программ (если мы ограничиваемся 1-категорией). Kind * это как раз класс-универсум всех типов, то есть объектов Hask, так что выхлоп GHCi [] :: * -> * на :k [] это, натурально, [] : Hask -> Hask, то есть повод задуматься о том, что конструктор типов [] это эндофунктор на Hask (это нужно доказать основываясь на индуктивном определении []).
Исправление quasimoto, :
Сам я пишу на C++ и привык читать инстанцирование класса, как «ConcreteObject - это SomeClass». Как мне показалось, в haskell так делать нельзя.
То что в C++ называется классами и объектами в Haskell называется ADT и значениями (термами).
Например, такой код с классами, объектами и методами:
#include <cstdio>
struct a_t {
int x, y;
int sum() { return x + y; }
};
class ab_t {
// @tagged_union
enum { a_tag, b_tag } tag;
union {
a_t a;
struct {
int x, y, z;
int sum() { return x + y + z; }
} b;
} ab_u;
public:
ab_t(a_t a_) : tag(a_tag) { ab_u.a = a_; }
ab_t(int x_, int y_, int z_) : tag(b_tag) { ab_u.b = { x_, y_, z_ }; }
int sum() { return tag == a_tag ? ab_u.a.sum() : ab_u.b.sum(); }
};
int main()
{
ab_t ab1({1, 2});
ab_t ab2(3, 4, 5);
printf("ab1.sum = %d; ab2.sum = %d\n", ab1.sum(), ab2.sum());
}
В Haskell переводится в код с ADT, значениями и функциями:
import Text.Printf
data A = A Int Int
data AB = A_ A | B Int Int Int
a_ :: Int -> Int -> AB
a_ x y = A_ $ A x y
sumA :: A -> Int
sumA (A x y) = x + y
sumAB :: AB -> Int
sumAB (A_ a) = sumA a
sumAB (B x y z) = x + y + z
main :: IO ()
main = printf "sumAB a = %d; sumAB b = %d\n" (sumAB $ a_ 1 2) (sumAB $ B 3 4 5)
«объект класса» превращается в «терм/значение (алгебраического) типа».
Разница между классами и методами C++ и ADT и функциями Haskell в том, что в C++ может легко начаться наследование, подтипирование и динамическая диспетчеризация, тогда как в Haskell это делается не так легко.
Теперь, если применить в Haskell концепцию классов типов:
class Sum t where
sumt :: t -> Int
instance Sum A where
sumt (A x y) = x + y
instance Sum AB where
sumt (A_ a) = sumt a
sumt (B x y z) = x + y + z
main :: IO ()
main = printf "sum a = %d; sum b = %d\n" (sumt $ a_ 1 2) (sumt $ B 3 4 5)
то, наоборот, в С++ это уже не так легко. Классы типов не имеют отношения к классам С++, они имеют отношения к интерфейсам и концептам - первые в С++ довольно неудобны:
struct sum_i {
virtual ~sum_i() {}
virtual int sum() const = 0;
};
struct a_t : public sum_i {
int x, y;
a_t(int x_, int y_) : x(x_), y(y_) {}
int sum() const { return x + y; }
};
class ab_t : public sum_i {
// ?
};
а вторых ещё нет (про функторы на них можно посмотреть тут - http://www.pik-potsdam.de/members/lincke/papers/Lincke_et_al_SCP.pdf).
говорит о том что для типа [] определен функтор осуществляющий отображение стрелок над элементами списка в стрелки над списками
[] это и есть функтор - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.103.9637. Класс типов Functor это не функтор и не тип, если мы его интернализируем в язык, это будет класс. То есть если 5 :: Int :: * :: **, тогда Functor :: (* -> *) -> ** (Functor :: (* -> *) -> Constraint в нынешнем GHC, то есть оно там «constraint»).
В зависимости от того, каким функтором является ADT, можно про него сказать разные вещи, в том числе, является ли этот ADT хорошим, то есть не приведёт ли его существование к противоречиям в языке («строго-позитивные функторы»).
А сущность Functor это вещь (класс/constraint) которая нужна либо для того чтобы принять на веру что данный ADT это функтор, объявить функторный интерфейс и реализовать его для данного ADT, либо для того чтобы _доказать_ что данный ADT это функтор (ну и тоже - объявить функторный интерфейс и реализовать его для данного ADT).
«для типа Something инстанцирован/описан/реализован Functor», но не «Something - это Functor»?
Тип Something :: * -> * это функтор (с маленькой буквы и если это ещё функтор, конечно), что подтверждается существованием для этого типа инстанса класса типов (класса) Functor (с большой буквы), если в языке выразимы аксиомы функтора это будет буквальным подтверждением, то есть строгим доказательством того что Something - функтор.
Ну и почему в классе Functor описано отображение для стрелок, но не описано отображение для объектов (как pure из класса Applicative)?
Отображением стрелок/значений/конструкторов/термов/функций/программ занимается стрелка/функция/программа fmap :: (a -> b) -> ([ a ] -> [ b ]) в рантайме, отображением объектов/типов занимается функтор/конструктор типов [] :: * -> * во время компиляции. Все Functor, Pointed, Applicative, Monad описывают, на самом деле, только эндофункторы только одной категории Hask - категории всех типов и термов/конструкторов/классов эквивалентности функций-программ (если мы ограничиваемся 1-категорией). Kind * это как раз класс-универсум всех типов, то есть объектов Hask, так что выхлоп GHCi [] :: * -> * на :k [] это, натурально, [] : Hask -> Hask, то есть повод задуматься о том, что конструктор типов [] это эндофунктор на Hask (это нужно доказать основываясь на индуктивном определении []).
Исправление quasimoto, :
Сам я пишу на C++ и привык читать инстанцирование класса, как «ConcreteObject - это SomeClass». Как мне показалось, в haskell так делать нельзя.
То что в C++ называется классами и объектами в Haskell называется ADT и значениями (термами).
Например, такой код с классами, объектами и методами:
#include <cstdio>
struct a_t {
int x, y;
int sum() { return x + y; }
};
class ab_t {
// @tagged_union
enum { a_tag, b_tag } tag;
union {
a_t a;
struct {
int x, y, z;
int sum() { return x + y + z; }
} b;
} ab_u;
public:
ab_t(a_t a_) : tag(a_tag) { ab_u.a = a_; }
ab_t(int x_, int y_, int z_) : tag(b_tag) { ab_u.b = { x_, y_, z_ }; }
int sum() { return tag == a_tag ? ab_u.a.sum() : ab_u.b.sum(); }
};
int main()
{
ab_t ab1({1, 2});
ab_t ab2(3, 4, 5);
printf("ab1.sum = %d; ab2.sum = %d\n", ab1.sum(), ab2.sum());
}
В Haskell переводится в код с ADT, значениями и функциями:
import Text.Printf
data A = A Int Int
data AB = A_ A | B Int Int Int
a_ :: Int -> Int -> AB
a_ x y = A_ $ A x y
sumA :: A -> Int
sumA (A x y) = x + y
sumAB :: AB -> Int
sumAB (A_ a) = sumA a
sumAB (B x y z) = x + y + z
main :: IO ()
main = printf "sumAB a = %d; sumAB b = %d\n" (sumAB $ a_ 1 2) (sumAB $ B 3 4 5)
«объект класса» превращается в «терм/значение (алгебраического) типа».
Разница между классами и методами C++ и ADT и функциями Haskell в том, что в C++ может легко начаться наследование, подтипирование и динамическая диспетчеризация, тогда как в Haskell это делается не так легко.
Теперь, если применить в Haskell концепцию классов типов:
class Sum t where
sumt :: t -> Int
instance Sum A where
sumt (A x y) = x + y
instance Sum AB where
sumt (A_ a) = sumt a
sumt (B x y z) = x + y + z
main :: IO ()
main = printf "sum a = %d; sum b = %d\n" (sumt $ a_ 1 2) (sumt $ B 3 4 5)
то, наоборот, в С++ это уже не так легко. Классы типов не имеют отношения к классам С++, они имеют отношения к интерфейсам и концептам - первые в С++ довольно неудобны:
struct sum_i {
virtual ~sum_i() {}
virtual int sum() const = 0;
};
struct a_t : public sum_i {
int x, y;
a_t(int x_, int y_) : x(x_), y(y_) {}
int sum() const { return x + y; }
};
class ab_t : public sum_i {
// ?
};
а вторых ещё нет (про функторы на них можно посмотреть тут - http://www.pik-potsdam.de/members/lincke/papers/Lincke_et_al_SCP.pdf).
говорит о том что для типа [] определен функтор осуществляющий отображение стрелок над элементами списка в стрелки над списками
[] это и есть функтор - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.103.9637. Класс типов Functor это не функтор и не тип, если мы его интернализируем в язык, это будет класс. То есть если 5 :: Int :: * :: **, тогда Functor :: (* -> *) -> ** (Functor :: (* -> *) -> Constraint в нынешнем GHC).
В зависимости от того, каким функтором является ADT, можно про него сказать разные вещи, в том числе, является ли этот ADT хорошим, то есть не приведёт ли его существование к противоречиям в языке («строго-позитивные функторы»).
А сущность Functor это вещь (класс) которая нужна либо для того чтобы принять на веру что данный ADT это функтор, объявить функторный интерфейс и реализовать его для данного ADT, либо для того чтобы _доказать_ что данный ADT это функтор (ну и тоже - объявить функторный интерфейс и реализовать его для данного ADT).
«для типа Something инстанцирован/описан/реализован Functor», но не «Something - это Functor»?
Тип Something :: * -> * это функтор (с маленькой буквы и если это ещё функтор, конечно), что подтверждается существованием для этого типа инстанса класса типов (класса) Functor (с большой буквы), если в языке выразимы аксиомы функтора это будет буквальным подтверждением, то есть строгим доказательством того что Something - функтор.
Ну и почему в классе Functor описано отображение для стрелок, но не описано отображение для объектов (как pure из класса Applicative)?
Отображением стрелок/значений/конструкторов/термов/функций/программ занимается стрелка/функция/программа fmap :: (a -> b) -> ([ a ] -> [ b ]) в рантайме, отображением объектов/типов занимается функтор/конструктор типов [] :: * -> * во время компиляции. Все Functor, Pointed, Applicative, Monad описывают, на самом деле, только эндофункторы только одной категории Hask - категории всех типов и термов/конструкторов/классов эквивалентности функций-программ (если мы ограничиваемся 1-категорией). Kind * это как раз класс-универсум всех типов, то есть объектов Hask, так что выхлоп GHCi [] :: * -> * на :k [] это, натурально, [] : Hask -> Hask, то есть повод задуматься о том, что конструктор типов [] это эндофунктор на Hask (это нужно доказать основываясь на индуктивном определении []).
Исправление quasimoto, :
Сам я пишу на C++ и привык читать инстанцирование класса, как «ConcreteObject - это SomeClass». Как мне показалось, в haskell так делать нельзя.
То что в C++ называется классами и объектами в Haskell называется ADT и значениями (термами).
Например, такой код с классами, объектами и методами:
#include <cstdio>
struct a_t {
int x, y;
int sum() { return x + y; }
};
class ab_t {
// @tagged_union
enum { a_tag, b_tag } tag;
union {
a_t a;
struct {
int x, y, z;
int sum() { return x + y + z; }
} b;
} ab_u;
public:
ab_t(a_t a_) : tag(a_tag) { ab_u.a = a_; }
ab_t(int x_, int y_, int z_) : tag(b_tag) { ab_u.b = { x_, y_, z_ }; }
int sum() { return tag == a_tag ? ab_u.a.sum() : ab_u.b.sum(); }
};
int main()
{
ab_t ab1({1, 2});
ab_t ab2(3, 4, 5);
printf("ab1.sum = %d; ab2.sum = %d\n", ab1.sum(), ab2.sum());
}
В Haskell переводится в код с ADT, значениями и функциями:
import Text.Printf
data A = A Int Int
data AB = A_ A | B Int Int Int
a_ :: Int -> Int -> AB
a_ x y = A_ $ A x y
sumA :: A -> Int
sumA (A x y) = x + y
sumAB :: AB -> Int
sumAB (A_ a) = sumA a
sumAB (B x y z) = x + y + z
main :: IO ()
main = printf "sumAB a = %d; sumAB b = %d\n" (sumAB $ a_ 1 2) (sumAB $ B 3 4 5)
«объект класса» превращается в «терм/значение (алгебраического) типа».
Разница между классами и методами C++ и ADT и функциями Haskell в том, что в C++ может легко начаться наследование, подтипирование и динамическая диспетчеризация, тогда как в Haskell это делается не так легко.
Теперь, если применить в Haskell концепцию классов типов:
class Sum t where
sumt :: t -> Int
instance Sum A where
sumt (A x y) = x + y
instance Sum AB where
sumt (A_ a) = sumt a
sumt (B x y z) = x + y + z
main :: IO ()
main = printf "sum a = %d; sum b = %d\n" (sumt $ a_ 1 2) (sumt $ B 3 4 5)
то, наоборот, в С++ это уже не так легко. Классы типов не имеют отношения к классам С++, они имеют отношения к интерфейсам и концептам - первые в С++ довольно неудобны:
struct sum_i {
virtual ~sum_i() {}
virtual int sum() const = 0;
};
struct a_t : public sum_i {
int x, y;
a_t(int x_, int y_) : x(x_), y(y_) {}
int sum() const { return x + y; }
};
class ab_t : public sum_i {
// ?
};
а вторых ещё нет (про функторы на них можно посмотреть тут - http://www.pik-potsdam.de/members/lincke/papers/Lincke_et_al_SCP.pdf).
говорит о том что для типа [] определен функтор осуществляющий отображение стрелок над элементами списка в стрелки над списками
[] это и есть функтор - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.103.9637. Класс типов Functor это не функтор и не тип, если мы его интернализируем в язык, это будет класс. То есть если 5 :: Int :: * :: **, тогда Functor :: * -> **.
В зависимости от того, каким функтором является ADT, можно про него сказать разные вещи, в том числе, является ли этот ADT хорошим, то есть не приведёт ли его существование к противоречиям в языке («строго-позитивные функторы»).
А сущность Functor это вещь (класс) которая нужна либо для того чтобы принять на веру что данный ADT это функтор, объявить функторный интерфейс и реализовать его для данного ADT, либо для того чтобы _доказать_ что данный ADT это функтор (ну и тоже - объявить функторный интерфейс и реализовать его для данного ADT).
«для типа Something инстанцирован/описан/реализован Functor», но не «Something - это Functor»?
Тип Something :: * -> * это функтор (с маленькой буквы и если это ещё функтор, конечно), что подтверждается существованием для этого типа инстанса класса типов (класса) Functor (с большой буквы), если в языке выразимы аксиомы функтора это будет буквальным подтверждением, то есть строгим доказательством того что Something - функтор.
Ну и почему в классе Functor описано отображение для стрелок, но не описано отображение для объектов (как pure из класса Applicative)?
Отображением стрелок/значений/конструкторов/термов/функций/программ занимается стрелка/функция/программа fmap :: (a -> b) -> ([ a ] -> [ b ]) в рантайме, отображением объектов/типов занимается функтор/конструктор типов [] :: * -> * во время компиляции. Все Functor, Pointed, Applicative, Monad описывают, на самом деле, только эндофункторы только одной категории Hask - категории всех типов и термов/конструкторов/классов эквивалентности функций-программ (если мы ограничиваемся 1-категорией). Kind * это как раз класс-универсум всех типов, то есть объектов Hask, так что выхлоп GHCi [] :: * -> * на :k [] это, натурально, [] : Hask -> Hask, то есть повод задуматься о том, что конструктор типов [] это эндофунктор на Hask (это нужно доказать основываясь на индуктивном определении []).
Исходная версия quasimoto, :
Сам я пишу на C++ и привык читать инстанцирование класса, как «ConcreteObject - это SomeClass». Как мне показалось, в haskell так делать нельзя.
То что в C++ называется классами и объектами в Haskell называется ADT и значениями (термами).
Например, такой код с классами, объектами и методами:
#include <cstdio>
struct a_t {
int x, y;
int sum() { return x + y; }
};
class ab_t {
// @tagged_union
enum { a_tag, b_tag } tag;
union {
a_t a;
struct {
int x, y, z;
int sum() { return x + y + z; }
} b;
} ab_u;
public:
ab_t(a_t a_) : tag(a_tag) { ab_u.a = a_; }
ab_t(int x_, int y_, int z_) : tag(b_tag) { ab_u.b = { x_, y_, z_ }; }
int sum() { return tag == a_tag ? ab_u.a.sum() : ab_u.b.sum(); }
};
int main()
{
ab_t ab1({1, 2});
ab_t ab2(3, 4, 5);
printf("ab1.sum = %d; ab2.sum = %d\n", ab1.sum(), ab2.sum());
}
В Haskell переводится в код с ADT, значениями и функциями:
import Text.Printf
data A = A Int Int
data AB = A_ A | B Int Int Int
a_ :: Int -> Int -> AB
a_ x y = A_ $ A x y
sumA :: A -> Int
sumA (A x y) = x + y
sumAB :: AB -> Int
sumAB (A_ a) = sumA a
sumAB (B x y z) = x + y + z
main :: IO ()
main = printf "sumAB a = %d; sumAB b = %d\n" (sumAB $ a_ 1 2) (sumAB $ B 3 4 5)
«объект класса» превращается в «терм/значение (алгебраического) типа».
Разница между классами и методами C++ и ADT и функциями Haskell в том, что в C++ может легко начаться наследование, подтипирование и динамическая диспетчеризация, тогда как в Haskell это делается не так легко.
Теперь, если применить в Haskell концепцию классов типов:
class Sum t where
sumt :: t -> Int
instance Sum A where
sumt (A x y) = x + y
instance Sum AB where
sumt (A_ a) = sumt a
sumt (B x y z) = x + y + z
main :: IO ()
main = printf "sum a = %d; sum b = %d\n" (sumt $ a_ 1 2) (sumt $ B 3 4 5)
то, наоборот, в С++ это уже не так легко. Классы типов не имеют отношения к классам С++, они имеют отношения к интерфейсам и концептам - первые в С++ довольно неудобны:
struct sum_i {
virtual ~sum_i() {}
virtual int sum() const = 0;
};
struct a_t : public sum_i {
int x, y;
a_t(int x_, int y_) : x(x_), y(y_) {}
int sum() const { return x + y; }
};
class ab_t : public sum_i {
// ?
};
а вторых ещё нет (про функторы на них можно посмотреть тут - http://www.pik-potsdam.de/members/lincke/papers/Lincke_et_al_SCP.pdf).
говорит о том что для типа [] определен функтор осуществляющий отображение стрелок над элементами списка в стрелки над списками
[] это и есть функтор - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.103.9637. Класс типов Functor это не функтор и не тип, если мы его интернализируем в язык, это будет класс. То есть если 5 :: Int :: * :: **, тогда Functor :: * -> **.
В зависимости от того, каким функтором является ADT, можно про него сказать разные вещи, в том числе, является ли этот ADT хорошим, то есть не приведёт ли его существование к противоречиям в языке («строго-позитивные функторы»).
А сущность Functor это вещь (класс) которая нужна либо для того чтобы принять на веру что данный ADT это функтор, объявить функторный интерфейс и реализовать его для данного ADT, либо для того чтобы _доказать_ что данный ADT это функтор (ну и тоже - объявить функторный интерфейс и реализовать его для данного ADT).
«для типа Something инстанцирован/описан/реализован Functor», но не «Something - это Functor»?
Тип Something :: * -> * это функтор (с маленькой буквы и если это ещё функтор, конечно), что подтверждается существованием для этого типа инстанса класса типов (класса) Functor (с большой буквы), если в языке выразимы аксиомы функтора это будет буквальным подтверждением, то есть строгим доказательством того что Something - функтор.
Ну и почему в классе Functor описано отображение для стрелок, но не описано отображение для объектов (как pure из класса Applicative)?
Отображением стрелок/значений/конструкторов/термов/функций/программ занимается стрелка/функция/программа fmap :: (a -> b) -> ([a] -> ) в рантайме, отображением объектов/типов занимается функтор/конструктор типов [] :: * -> * во время компиляции. Все Functor, Pointed, Applicative, Monad описывают, на самом деле, только эндофункторы только одной категории Hask - категории всех типов и термов/конструкторов/классов эквивалентности функций-программ (если мы ограничиваемся 1-категорией). Kind * это как раз класс-универсум всех типов, то есть объектов Hask, так что выхлоп GHCi [] :: * -> * на :k [] это, натурально, [] : Hask -> Hask, то есть повод задуматься о том, что конструктор типов [] это эндофунктор на Hask (это нужно доказать основываясь на индуктивном определении []).