and more on type classes in Scala
Jan. 23rd, 2013 07:37 pmThis part is not exactly a theory of algebraic theories, but anyway.
Imagine we have a parametric class (e.g.
Suppose we want to declare
The trick would be to have an implicit transformation handy that transforms
Where can we find such a general transformation? The only thing that comes up to mind is an identity:
This would be enough in this specific case... but then we would have to define another one for numeric types, and so on.
We can go generic, and write something like this:
Now we can define
All the conditions are satisfied now. Contravariance in the first argument and covariance in the second argument ensure that a subtype can be cast to its supertype... to be more precise, an instance of supertype can be substituted by an instance of subtype.
The only thing is that we can try to make the code more readable, by refactoring.
Step 1. Use the trick in Scala that binary operations can be written in an infix way, even for types. E.g. you can declare
Step 2. Rename the method, giving it a more "type-relationship" name:
That's the trick.
(if you have questions, ask; if you have corrections, please tell me)
Imagine we have a parametric class (e.g.
List[X]) for which we would like to define methods that would only work if X satisfies certain conditions. E.g. define sum if it is a numeric type, or define flatten if it is some kind of sequence (Traversable[Y] would be enough). How can we accomplish it in Scala?!Suppose we want to declare
flatten
trait List[X] {
// bla-bla-bla
def flatten[X <% Iterable[Y]] { ... } // no way, we already mentioned X; this one would shadow the previous one
// OOPS!
}
The trick would be to have an implicit transformation handy that transforms
X into Iterable[Y] for some Y; and define it so that if X is actually some kind of Iterable, the implicit would be available, and otherwise not available.Where can we find such a general transformation? The only thing that comes up to mind is an identity:
implicit def itsme[Y, X <% Iterable[Y]](x: X): Iterable[Y] = xThis would be enough in this specific case... but then we would have to define another one for numeric types, and so on.
We can go generic, and write something like this:
abstract class SafeToCast[-S, +T] extends Function1[S, T]
implicit def canCast[X <% Y, Y]: SafeToCast[X, Y] = new SafeToCast[X,Y] { def apply(x:X) = x }
Now we can define
flatten, like this:
class List[X] { ...
def flatten[Y](implicit transformer: SafeToCast[X, Iterable[Y]]) { ... }
}
All the conditions are satisfied now. Contravariance in the first argument and covariance in the second argument ensure that a subtype can be cast to its supertype... to be more precise, an instance of supertype can be substituted by an instance of subtype.
The only thing is that we can try to make the code more readable, by refactoring.
Step 1. Use the trick in Scala that binary operations can be written in an infix way, even for types. E.g. you can declare
val map: (String Map Int) - this is the same as Map[String, Int].
sealed abstract class SafeToCast[-S, +T] extends Function1[S, T]
implicit def canCast[X <% Y, Y]: (X SafeToCast Y) = new (X SafeToCast Y) { def apply(x: X) = a }
...
class List[X] { ...
def flatten[Y](implicit transformer: X SafeToCast Iterable[Y]) { ... }
}
Step 2. Rename the method, giving it a more "type-relationship" name:
SafeToCast -> <:<.
sealed abstract class <:<[-S, +T] extends Function1[S, T]
implicit def canCast[X <% Y, Y]: (X <:< Y) = new (X <:< Y) { def apply(x: X) = a }
...
class List[X] { ...
def flatten[Y](implicit transformer: X <:< Iterable[Y]) { ... }
}
That's the trick.
(if you have questions, ask; if you have corrections, please tell me)
type classes as I see them in Scala
Jan. 21st, 2013 09:12 pmSpent a couple of weeks trying to figure out what exactly is it. Looked it up in Wikipedia, in Scala, in Haskell, in popular articles. Now I think I know what it is; here's my vision. Please pardon my English and my cheap, simplified Math.
1. Type Class is an Algebraic Theory
An algebraic theory is a rather abstract notion. It consists of variables of one or more types, a collection of operations, and a collections of axioms.
1.1. Example
Monoid. Just one variable type; two operations: a binary operation and a nullary operation (that produces a neutral element), and axioms: associativity and neutral element neutrality. Integer numbers can be perceived as a monoid, say, using multiplication as the binary operation and 1 as the neutral element.
1.2. Example
Vector space over a field. We have two types of variables, vectors and scalars. Scalars can add, subtract, multiply, divide, have a zero, a one; vectors can add, subtract, have a zero, can be multiplied by a scalar. We can also throw in scalar product of two vectors.
2. But Can We Express A Theory As Trait (interface, in Java)?
On many occasions, yes. You can define a pure abstract trait (or, in Java, just an interface) that defines the operations, e.g. for a monoid:
Notice, we do not specify any axioms. In languages like Scala, Haskell, Java, we cannot. It takes Agda to handle axioms.
We have a problem here that the if we try to introduce a specific kind of monoid, the result of binOp does not belong to that kind; so we have to be more careful and design our trait keeping in mind we are going to extend it, like this:
Now we can define something like
It works... but well, the new class is not exactly a
Suppose for a moment we could (we can do it in JavaScript ad libitum). What would we do with Ints then? What binary operation, addition? multiplication? min? max? There might be more.
Now let's disambiguate.
2 3. Model
When we defined a trait without implementation, we described a theory. When we started building specific implementations, we define a model for our theory. There may many models for the same theory; the same structure may be a model of a variety of theories. We have to be able to express this relationship.
In the example above we made
In Haskell, models are called instances (of a type class); in C++0x (please excuse my misspelling) they are called models (and theories are called concepts).
In Haskell one can define
and model it with lists (strings are lists in Haskell):
We can do it in Scala, kind of more verbosely.
In one case we used one
3. Important Remark
We could probably start thinking, hmm, how about just parameterized types, what's the difference? Say, take
Not exactly. It is a totally different thing, unfortunately written in the same style. Here we have a functor: given a type
While we could make it into a type class, if the polymorphism here were ad-hoc, we normally do not.
4. That's Not It Yet
Next I'll show how we can restrict the scope of certain operations to certain subtypes, of the type that we pass as a parameter.
please correct me where I'm wrong
1. Type Class is an Algebraic Theory
An algebraic theory is a rather abstract notion. It consists of variables of one or more types, a collection of operations, and a collections of axioms.
1.1. Example
Monoid. Just one variable type; two operations: a binary operation and a nullary operation (that produces a neutral element), and axioms: associativity and neutral element neutrality. Integer numbers can be perceived as a monoid, say, using multiplication as the binary operation and 1 as the neutral element.
1.2. Example
Vector space over a field. We have two types of variables, vectors and scalars. Scalars can add, subtract, multiply, divide, have a zero, a one; vectors can add, subtract, have a zero, can be multiplied by a scalar. We can also throw in scalar product of two vectors.
2. But Can We Express A Theory As Trait (interface, in Java)?
On many occasions, yes. You can define a pure abstract trait (or, in Java, just an interface) that defines the operations, e.g. for a monoid:
trait Monoid {
def neutral: Monoid
def binOp(another: Monoid): Monoid
}
Notice, we do not specify any axioms. In languages like Scala, Haskell, Java, we cannot. It takes Agda to handle axioms.
We have a problem here that the if we try to introduce a specific kind of monoid, the result of binOp does not belong to that kind; so we have to be more careful and design our trait keeping in mind we are going to extend it, like this:
trait Monoid[Actual] {
def neutral: Actual
def binOp(another: Actual): Actual
}
Now we can define something like
class StringConcatMonoid(val s: String) extends Monoid[StringConcatMonoid] {
def neutral = new StringConcatMonoid("")
def binOp(another: StringConcatMonoid) = new StringConcatMonoid(s + another.s)
}
It works... but well, the new class is not exactly a
String class, right? That's the problem, we cannot throw in the new functionality into String. Suppose for a moment we could (we can do it in JavaScript ad libitum). What would we do with Ints then? What binary operation, addition? multiplication? min? max? There might be more.
Now let's disambiguate.
When we defined a trait without implementation, we described a theory. When we started building specific implementations, we define a model for our theory. There may many models for the same theory; the same structure may be a model of a variety of theories. We have to be able to express this relationship.
In the example above we made
StringConcatMonoid a model of Monoid theory. We were lucky, we had just one type; imagine we had more than one. Then there's no way to inherit anything. And we are still not happy that we cannot define binOp on Strings themselves; we look at Haskell, and seems like they do it easily.In Haskell, models are called instances (of a type class); in C++0x (please excuse my misspelling) they are called models (and theories are called concepts).
In Haskell one can define
class Monoid m where
binOp :: m -> m -> m
neutral :: m
and model it with lists (strings are lists in Haskell):
instance Monoid [a] where
binOp = (++)
neutral = []
We can do it in Scala, kind of more verbosely.
object A {
implicit object addMonoid extends Monoid [Int] {
def binOp (x :Int,y :Int) = x+y
def neutral = 0
}
}
object B {
implicit object multMonoid extends Monoid [Int] {
def binOp (x :Int,y :Int) = x ∗ y
def neutral = 1
}
}
val test :(Int,Int,Int) = {
{
import A._
println(binOp(2, 3))
}
{
import B._
println(binOp(2, 3))
}
}
In one case we used one
binOp, in another we used another. We can define fold that implicitly accepts an instance of Monoid, and provides the required operation, but that's beyond the topic of this talk.3. Important Remark
We could probably start thinking, hmm, how about just parameterized types, what's the difference? Say, take
List[T], is not it a type class? We have abstract operations, independent of the type T, and so it is also not a specific type, but a class of types, right?Not exactly. It is a totally different thing, unfortunately written in the same style. Here we have a functor: given a type
T, we produce another type, List[T], uniquely determined by the type T, and whose operations (almost) do not depend on what is T.While we could make it into a type class, if the polymorphism here were ad-hoc, we normally do not.
4. That's Not It Yet
Next I'll show how we can restrict the scope of certain operations to certain subtypes, of the type that we pass as a parameter.
please correct me where I'm wrong
typeclasses take 2
Jan. 14th, 2013 11:42 pmСидит Андрей Петрович Ощепков на крутом бережку Енисея и читает книжку "Гильбертовы Пространства в Задачах и Решениях"; подходит мужик, глядит на обложку, и спрашивает Андрея Петровича: "а шо це за параша, Гильбертовы Пространства?"
/Эпиграф/
/Эпиграф/
Итак, мой предыдущий пост я практически объявляю полной фигнёй.
Кроме одной фразы - type class - это класс типов. Остальное фигня.
Как я понимаю, класс типов можно определить а) параметрически: List[T] - это класс списков с элементами типа T; в хаскеле для этого есть лихой термин type family b) через уравнение:
class Eq a ...; в скале это можно задать приблизительно.Сегодня Дэвид Анджеевски на скальном митапе вообще задвинул термин type class pattern, и на мой вопрос, не знает ли он формального определения тайпкласса сказал, что нет, не знает.
Вот ещё линки.
typeclassopedia, by John Kodumal, Atlassian - слов и примеров много, определения нет.
что сказал Дебасиш - это типа скорее паттерн тоже
Stackoverflow: какая польза от тайпклассов? ("а сёдла на них есть?")
Moors, Pissens, Oderski, "Generics of Higher Kind" - тут скорее намёки на тему тайпклассов, наряду с техничным рассуждением на тему шо в скале уже таки есть
"oop vs typeclasses" - по мне так скорее философия, с намёками, что, э, может быть таки тайпклассы - это параметризованные типы, не?
gentle haskell - здесь объясняют, что как раз не, объявляем через уравнения, а определяем или параметрически, или адхок.
Ну вы поняли, да? Я не понял. Только вижу, что тайпклассы - это что-то вроде многообразий, и не пора ли уже просто откровенно пойти пошукать шо за гомотопическая теория типов такая, и не отвечает ли она на вопросы.
Надеюсь на продуктивную дискуссию.
no closures in java 8 actually
Jan. 2nd, 2013 10:47 amhttps://groups.google.com/forum/?fromgroups=#!topic/scala-user/nC263xUiaQo
The same dumb stupid Java where you can only pass a final into an internal class...
"
The compiler error is: "value used in lambda expression should be effectively final". I got some bad suspicion and tried whether this compiles:
This did compile.
"
The same dumb stupid Java where you can only pass a final into an internal class...
"
List<Integer> ints = new ArrayList<>();
ints.add(1);
ints.add(2);
ints.add(3);
int sum = 0;
ints.forEach(i -> {sum += i;});
The compiler error is: "value used in lambda expression should be effectively final". I got some bad suspicion and tried whether this compiles:
int sumArray[] = new int[] { 0 };
ints.forEach(i -> {sumArray[0] += i;});
This did compile.
"
(from scala-user)
Can someone tell me whether this "gotcha" is type-unsafe or am I just not realizing something? This bit me in production code today (via java interop).
Year 2020:
Can someone tell me whether this "gotcha" is type-unsafe or am I just not realizing something? This bit me in production code today (via java interop).
scala> def x: java.math.BigDecimal = null x: java.math.BigDecimal scala> def y = Option[BigDecimal](x) orElse Option[BigDecimal](x) y: Option[BigDecimal] scala> for (z <- y) println(z) java.lang.NullPointerException
Year 2020:
... java.lang.IllegalArgumentException: null value for BigDecimal at scala.math.BigDecimal.(BigDecimal.scala:406) at scala.math.BigDecimal$.apply(BigDecimal.scala:335) at scala.math.BigDecimal$.apply(BigDecimal.scala:332) at scala.math.BigDecimal$.javaBigDecimal2bigDecimal(BigDecimal.scala:347) at .y( :12) ... 28 elided
state continuation monad
Sep. 25th, 2012 04:13 pmКиселёв сказал.
Это я еду со стрейнджлупа, в Сент Луисе; играет джаз и накрапывает дождик.
С утра послушал Никиту Иванова, как их гридгейн распределяет мапредьюс играючи. Никита, по знатному русскому обычаю, код прямо по ходу дела писал и гонял, распараллеливая.
Впечатляет, конечно. Но какое-то недоумение висит.
Потом был доклад о скале на llvm. Есть плюсы - не надо хитрить с трейтами, и функции можно нормально передавать. Но данные все забоксены. И библиотека джавная... Ну, нейтивы-то переписывать надо.
Потом был доклад про правильную арифметику для десятой скалы, со специвлизацией и без глюков.
Один философ рассказал, что скала олицетворяет слияние аристотелевой философии с сократовской, а венчает всё монада.
И ещё, говорит, джаваскрипт - тоже сократовская вещь.
Потом я пошел в другую аудиторию, на второй этаж, но лестница была забита народом. Это что, - спрашиваю, - на Киселёва очередь? Ага.
Но все влезли.
Киселёв код писал на окамле, но, говорит, мог бы и на си.
Речь шла о правильной ленивости. В качестве примера показывал генерацию палиндромов, распараллеленную и по Монте-Карло. А как результаты кешировать? А он использовал fork, так что в каждом процессе своё значение. А в скале надо бы было threadlocal. А в конце объяснил, что речь идёт о SCM - State Continuation Monad.
Открыл мне глаза. Я уже месяц кык пытался сообразить, как на скале или хаскеле кеш запрограммировать, без варов и без блядских этих threadlocals. А вот как. Ну теперь знаю, остаётся код написать.
Погятно, что Киселёв код писал тут же, по ходу дела, и гонял, распараллеоив и показывая top.
Это я еду со стрейнджлупа, в Сент Луисе; играет джаз и накрапывает дождик.
С утра послушал Никиту Иванова, как их гридгейн распределяет мапредьюс играючи. Никита, по знатному русскому обычаю, код прямо по ходу дела писал и гонял, распараллеливая.
Впечатляет, конечно. Но какое-то недоумение висит.
Потом был доклад о скале на llvm. Есть плюсы - не надо хитрить с трейтами, и функции можно нормально передавать. Но данные все забоксены. И библиотека джавная... Ну, нейтивы-то переписывать надо.
Потом был доклад про правильную арифметику для десятой скалы, со специвлизацией и без глюков.
Один философ рассказал, что скала олицетворяет слияние аристотелевой философии с сократовской, а венчает всё монада.
И ещё, говорит, джаваскрипт - тоже сократовская вещь.
Потом я пошел в другую аудиторию, на второй этаж, но лестница была забита народом. Это что, - спрашиваю, - на Киселёва очередь? Ага.
Но все влезли.
Киселёв код писал на окамле, но, говорит, мог бы и на си.
Речь шла о правильной ленивости. В качестве примера показывал генерацию палиндромов, распараллеленную и по Монте-Карло. А как результаты кешировать? А он использовал fork, так что в каждом процессе своё значение. А в скале надо бы было threadlocal. А в конце объяснил, что речь идёт о SCM - State Continuation Monad.
Открыл мне глаза. Я уже месяц кык пытался сообразить, как на скале или хаскеле кеш запрограммировать, без варов и без блядских этих threadlocals. А вот как. Ну теперь знаю, остаётся код написать.
Погятно, что Киселёв код писал тут же, по ходу дела, и гонял, распараллеоив и показывая top.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | function arrayFrom(list) { var out = []; for (i = 0; i < list.size(); i++) { out[i] = asJS(list.apply(i)) } return out; } function mapFrom(map) { var out = {}; var i = map.iterator(); while(i.hasNext()) { var e = i.next(); out[e._1()] = asJS(e._2()) } return out; } function isListlike(name) { return name.indexOf("List") >= 0 || name.indexOf("Array") >= 0 || name.indexOf("$colon$colon") >= 0 } function isMapLike(name) { return name.indexOf("Map") >= 0 } function asJS(obj) { try { var cn = obj.getClass().getSimpleName(); if (isListlike(cn)) return arrayFrom(obj); if (isMapLike(cn)) return mapFrom(obj); } catch (x) {} return obj; } |
critique?
пока сам не понимаю, что делаю
Aug. 8th, 2012 07:21 pmПишу на джавасприпте кусочки, которые через http post бросаю своему серверу, там рино их исполняет, вызывая мои методы на скале, каковые разговаривают с другим сервером и переформатируют варварские данные в простые мапы; что-то тут лишнее, но я пока не понял, что.
Главное, что идея писать эту хрень на моём любименьком джаваскрипте как-то очень медленно вползает в голову.
Только что вот написал функцию на джаваскрипте, которая превращает скальный список в джаваскриптовый массив (ну вы в курсе, в джаваскрипте на самом-то деле массивов нет).
Обожаю этот постмодерновый стиль. Три языка (четыре - там ещё shell). Ещё один - и сгожусь в члены правительства ПМР.
Главное, что идея писать эту хрень на моём любименьком джаваскрипте как-то очень медленно вползает в голову.
Только что вот написал функцию на джаваскрипте, которая превращает скальный список в джаваскриптовый массив (ну вы в курсе, в джаваскрипте на самом-то деле массивов нет).
Обожаю этот постмодерновый стиль. Три языка (четыре - там ещё shell). Ещё один - и сгожусь в члены правительства ПМР.
среди всех относительно ужасных траблов...
Aug. 2nd, 2012 09:43 pm...что последнее время меня так настойчиво окружают, один смешной - это remote scala actors seemingly not working on my mac.
Т.е. Я могу на пальцах накатать ремотного актёра, что там писать-то, положить его к себе на пришив, и он там целую неделю будет жужжать:
( Read more... )
и вполне общаться с желающими. Но запустил ту же хрень у себя на маке - и один репл не видит другого. Тьфу. Т.е. этот же актёр из того же репла виден, а из другого шиш.
Народ советует акку. Но акку надо привинчивать, осваивать и т.д. Освою, конечно, но через пару недель. А так, на скале я лучше накатаю веб-сервер, половина тех же актёров, те же строк двадцать займёт, делов-то, serializable.unapply... да я просто строки перебрасывать буду, мне для инструментации, пиши как хочешь.
Обидно, да.
Остальные траблы я перечислять не буду; всё это можно спокойно свалить на собственную глупость.
Единственно что параллельно читаю книгу Анны Смирновой, и как-то убедительно начинаю идентифицировать себя с одним печальным героем этого восхитительного романа, что, конечно, тоже доставляет лулзов.
Это пессимистический пост, и очень прошу пессимистическую часть не комментировать, а если есть идейки насчёт маков и актёров, то буду очень благодарен.
P.S. Да и хрен с ними с актёрами; написал сервер, теперь через браузер к своему реплу хожу, любо-дорого.
Т.е. Я могу на пальцах накатать ремотного актёра, что там писать-то, положить его к себе на пришив, и он там целую неделю будет жужжать:
( Read more... )
и вполне общаться с желающими. Но запустил ту же хрень у себя на маке - и один репл не видит другого. Тьфу. Т.е. этот же актёр из того же репла виден, а из другого шиш.
Народ советует акку. Но акку надо привинчивать, осваивать и т.д. Освою, конечно, но через пару недель. А так, на скале я лучше накатаю веб-сервер, половина тех же актёров, те же строк двадцать займёт, делов-то, serializable.unapply... да я просто строки перебрасывать буду, мне для инструментации, пиши как хочешь.
Обидно, да.
Остальные траблы я перечислять не буду; всё это можно спокойно свалить на собственную глупость.
Единственно что параллельно читаю книгу Анны Смирновой, и как-то убедительно начинаю идентифицировать себя с одним печальным героем этого восхитительного романа, что, конечно, тоже доставляет лулзов.
Это пессимистический пост, и очень прошу пессимистическую часть не комментировать, а если есть идейки насчёт маков и актёров, то буду очень благодарен.
P.S. Да и хрен с ними с актёрами; написал сервер, теперь через браузер к своему реплу хожу, любо-дорого.
сопряженные функторы-3
Jul. 25th, 2012 11:09 amИтак, если у нас имеются две категории, C и D, и два функтора,
Для сопряженной пары мы вывели два естественных преобразования,
Оказывается, если есть такие два естественных преобразования, для пары функторов, то они сопряжены.
Ну и правда, если есть
То же самое, по симметрии, проделывается и в другую сторону. Вообще, у меня тут половина рассуждений лишняя, потому что зеркальная симметрия ж (никаких бозонов).
Наши
Эти два чудесные свойства получаются в результате применения тех самых соответствий
У нас есть теперь всё для монады и комонады.
Монада делается путём композиции,
Единица оказывается единицей относительно монадного умножения, и умножение оказывается ассоциативно - всё это следует из описанных выше свойств сопряженных функторов.
Симметрично мы можем определить комонаду, путём композиции
Пример.
Возьмём категории C=Set и D=Set×Set - множества и пары множеств, и два функтора,
Первый функтор - диагональ, он множеству сопоставляет пару, состоящую из двух экземпляров оного, а второй паре множеств сопоставляет декартово произведение.
Эти два функтора сопряжены,
А именно, если есть
Какая ж тут у нас монада? Монада берёт множество
Кто любит симплициальные категории, увидит тут различные краюшки и рёбрушки, но это ладно, это мы лучше не будем трогать.
"Практический смысл" в программировании у этой монады вот какой: есть двоичный флаг; и наши данные от него зависят - в одном случае вызов возвращает
Вопросы?
(Завтра продолжу, хочу показать, как из монады можно построить сопряженную пару, и не одну.)
F: C → D и G: D → C, мы говорим, что эти два функтора образуют сопряженную пару, F ⊣ G если имеется взаимно-однозначное соответствиеF(X) → Y | <====> | X → G(Y) |
Для сопряженной пары мы вывели два естественных преобразования,
η: IdC → F;G и ε: G;F → IdD.Оказывается, если есть такие два естественных преобразования, для пары функторов, то они сопряжены.
Ну и правда, если есть
f: F(X) → Y, то приложим к нему G, получим G(f): G(F(X)) → G(Y), и соединим это с ηX: X → G(F(X)), получим ту самую X → G(Y).То же самое, по симметрии, проделывается и в другую сторону. Вообще, у меня тут половина рассуждений лишняя, потому что зеркальная симметрия ж (никаких бозонов).
Наши
ηX и εY обладают чудесными свойствами:![]() | ![]() |
Эти два чудесные свойства получаются в результате применения тех самых соответствий
α и β, что были нарисованы в первой серии - попробуйте сами.У нас есть теперь всё для монады и комонады.
Монада делается путём композиции,
T = F;G; это функтор T: C → C. В качестве монадной единицы годится уже появлявшаяся у нас η, а в качестве монадного умножения (a.k.a. flatten) возьмём μX = G(εF(X)): G(F(G(F(X)))) → G(F(X)).Единица оказывается единицей относительно монадного умножения, и умножение оказывается ассоциативно - всё это следует из описанных выше свойств сопряженных функторов.
Симметрично мы можем определить комонаду, путём композиции
U = G;F.Пример.
Возьмём категории C=Set и D=Set×Set - множества и пары множеств, и два функтора,
Δ(X) = (X,X) и Π((X,Y)) = X×Y.Первый функтор - диагональ, он множеству сопоставляет пару, состоящую из двух экземпляров оного, а второй паре множеств сопоставляет декартово произведение.
Эти два функтора сопряжены,
Δ ⊣Π.А именно, если есть
(f1,f2): (X,X) → (Y1, Y2), то это задаёт отображение X →Y1×Y2, и наоборот, отображение в декартово произведение Y1×Y2 задаёт пару отображений, по компонентам.Какая ж тут у нас монада? Монада берёт множество
X и сопоставляет ему X×X. Монадная единица - диагональ (η(x) = (x,x)), а монадное умножение, X×X×X×X → X×X строится, согласно картинкам из начала этой части, из ε: (Y1×Y2, Y1×Y2) →(Y1,Y2) - проектированием по первой и последней координатам. μ(x1,x2,x3,x4) = (x1,x4).Кто любит симплициальные категории, увидит тут различные краюшки и рёбрушки, но это ладно, это мы лучше не будем трогать.
"Практический смысл" в программировании у этой монады вот какой: есть двоичный флаг; и наши данные от него зависят - в одном случае вызов возвращает
Y1, а в другом Y2. Ну и если у нас есть функция, зависящая от того же флага, то нам надо как-то комбинировать и сплющивать; это же Reader Monad, сведённая к двоичному флагу. Ну вот эта монада и есть.Вопросы?
(Завтра продолжу, хочу показать, как из монады можно построить сопряженную пару, и не одну.)
смешные случаи со скалой
Jul. 21st, 2012 02:43 pmсижу балуюсь с удалёнными артистами (remote actors)
чё у меня есть - а линух, ну
p
И вот потыкал lsof -i :9000, взял пид, сказал kill -9 этот самый пид
В той скале, что бежала слушала на 9000, вижу вот такой концептуальный текст:
чё у меня есть - а линух, ну
p
И вот потыкал lsof -i :9000, взял пид, сказал kill -9 этот самый пид
В той скале, что бежала слушала на 9000, вижу вот такой концептуальный текст:
scala> /home/vlad/scala-2.9.2/bin/scala: line 161: 5766 Killed
"${JAVACMD:=java}" $JAVA_OPTS "${java_args[@]}" ${CPSELECT}${TOOL_CLASSPATH} -Dscala.usejavacp=true -Dscala.home="$SCALA_HOME" -Denv.emacs="$EMACS" $CYGWIN_JLINE_TERMINAL scala.tools.nsc.MainGenericRunner "$@"
Just observed a curious thing. I'm using 2.9.2 on my linux.
And what I see: I println a set of two elements; and on different runs the order is different.
I was totally confused, but then noticed Parallelizable is being used (somehow I do not have source code installed; not the best time today).
So what I think I see is this: the nondeterminism in listing set elements. Just a two-element set.
I think this is beautiful. I believe we just beat the axiom of choice, like in the old article by A.Scedrov, where he demonstrated that even for the choice of two AC does not always hold (in his case, though, there was a circular "time" involved).
The future is now.
And what I see: I println a set of two elements; and on different runs the order is different.
I was totally confused, but then noticed Parallelizable is being used (somehow I do not have source code installed; not the best time today).
So what I think I see is this: the nondeterminism in listing set elements. Just a two-element set.
I think this is beautiful. I believe we just beat the axiom of choice, like in the old article by A.Scedrov, where he demonstrated that even for the choice of two AC does not always hold (in his case, though, there was a circular "time" involved).
The future is now.

