2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3  След.
 
 Re: Mонады в javascript
Сообщение10.06.2015, 06:54 


11/12/14
893
arseniiv в сообщении #1025453 писал(а):
И теория категорий их заимствовала?


Не я именно про языки программирования. Допускаю что уже и кроме Хаскеля есть таковые где оно уместно - но даже в гугле если гуглить "монады программирование" все ссылки будут со словом Хаскель. :) Всё таки как вы и говорили оно на стыке всего что в Хаскеле присутствует - как чистое ФП, строгая типизация, так вывод типов, так синтаксис со всеми применениями, бинарными функциями и прочая. Взять даже тот пример - монадические то функции он по сути ввёл.... но они строго привязаны к одной конкретной монаде, т.к. кончаются return SimpleMonad( x ). Т.е. получается, чтобы они стали универсальными, надо еще в них надо передавать "конструктор монады", от чего еще всё раздуется в коде. А в хаскеле как я понимаю просто автовывод сработает исходя из того в каком контексте монадическая функция встретится.
В итоге игра стремительно теряет свечи, чем дальше пытаешься построить целостный пример. :)

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 17:44 
Заслуженный участник


27/04/09
28128
aa_dav в сообщении #1025524 писал(а):
бинарными функциями
? Если это про операции, так переопределение их есть много где, так же как и разная степень вывода типов и возможность указывать в интерфейсе метод класса (для return). Хотя и мало где всё разом, но время-то ещё есть!

aa_dav в сообщении #1025524 писал(а):
Т.е. получается, чтобы они стали универсальными, надо еще в них надо передавать "конструктор монады", от чего еще всё раздуется в коде.
Не всегда do заканчивается return что-то. :-)

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 19:14 


11/12/14
893
Хм, пришла идея. Конструктор можно в сам bind и запихать.
Так что проапгрейдил пример из статьи до следующего:

код: [ скачать ] [ спрятать ]
Используется синтаксис Javascript
// 1-p functions

function getnull( x )
{
        return null;
};

function getzero( x )
{
        return 0;
};

function add7( x )
{
        return x + 7;
};

function sub4( x )
{
        return x - 4;
};

// Monad constructors

function EmptyMonad( value )
{
        this.value = value;
        this.bind = function( func )
        {
                res = func( this.value );
                return new EmptyMonad( res );
        };
};

function MaybeMonad( value )
{
        this.value = value;
        this.bind = function( func )
        {
                if ( this.value == null )
                        res = null;
                else
                        res = func( this.value );
                return new MaybeMonad( res );
        };     
};

// tests

WScript.Echo( "EmptyMonad" );
WScript.Echo( new EmptyMonad( 10 ).value );
WScript.Echo( new EmptyMonad( 10 ).bind( getzero ).value );
WScript.Echo( new EmptyMonad( 10 ).bind( getzero ).bind( add7 ).value );
WScript.Echo( new EmptyMonad( 10 ).bind( function ( x ) { return 2 * x } ).value );

WScript.Echo( "MaybeMonad" );
WScript.Echo( new MaybeMonad( 10 ).value );
WScript.Echo( new MaybeMonad( 10 ).bind( getnull ).value );
WScript.Echo( new MaybeMonad( 10 ).bind( getnull ).bind( add7 ).value );
WScript.Echo( new MaybeMonad( 10 ).bind( getnull ).bind( add7 ).bind( sub4 ).value );
 


Чем JavaScript еще хорош - под любой виндой скопировать текст в файл с расширением *.js и щёлкнуть по нему.
Если охота видеть вывод в консоли, запускать из консоли через команду cscript file.js

Такс, но это далеко как грица не всё...

-- 10.06.2015, 20:32 --

Лёгкий апгрейд:

код: [ скачать ] [ спрятать ]
Используется синтаксис Javascript
// 1-p functions

function getnull( x )
{
        return null;
};

function getzero( x )
{
        return 0;
};

function add7( x )
{
        return x + 7;
};

function sub4( x )
{
        return x - 4;
};

// Monad constructors

function EmptyMonad( value )
{
        this.value = value;
        this.bind = function( func )
        {
                res = func( this.value );
                return new EmptyMonad( res );
        };
};

function MaybeMonad( value )
{
        this.value = value;
        this.bind = function( func )
        {
                if ( this.value == null )
                        res = null;
                else
                        res = func( this.value );
                return new MaybeMonad( res );
        };     
};

// tests

function test1( name, monad )
{
        WScript.Echo( name + " = " + monad.value );
        monad = monad.bind( add7 );
        WScript.Echo( "add7 = " + monad.value );
        monad = monad.bind( sub4 );
        WScript.Echo( "sub4 = " + monad.value );
        monad = monad.bind( getnull );
        WScript.Echo( "getnull = " + monad.value );
        monad = monad.bind( getzero );
        WScript.Echo( "getzero = " + monad.value );
        monad = monad.bind( function ( x ) { return x + 3 } );
        WScript.Echo( "custom+3 = " + monad.value );
};

function test2( name, monad )
{
        WScript.Echo( name + " with initial value " + monad.value + " bulk calculations: " +
                monad.bind( add7 ).bind( sub4 ).bind( getnull ).bind( getzero ).bind( function ( x ) { return x + 3 } ).value
        );
};

test1( "EmptyMonad", new EmptyMonad( 10 ) );
test2( "EmptyMonad", new EmptyMonad( 10 ) );
test1( "MaybeMonad", new MaybeMonad( 10 ) );
test2( "MaybeMonad", new MaybeMonad( 10 ) );
 

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 19:34 
Заслуженный участник


27/04/09
28128
aa_dav в сообщении #1025764 писал(а):
Хм, пришла идея. Конструктор можно в сам bind и запихать.
И, если правильно им потом пользоваться, получится, что возвращается m (m a). И никак это не превратить в m a, потому что join :: m (m a) -> m a как раз через bind и выражается (и наоборот), если его не определять вместе с — но в любом случае, они должны быть согласованы.

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 19:39 


11/12/14
893
arseniiv в сообщении #1025772 писал(а):
И, если правильно им потом пользоваться


А вот можно пример что потом по идее должно хотеться этим правильно воспользоваться?
.value написать там где надо "поднять значение наверх" тут никто не запрещает, другой синтаксис и правила в общем то.

-- 10.06.2015, 20:51 --

P.S.

Ну и да, то что в самом начале топика топикастер имитировал do-нотацию "как то странно", тут и имитировать не надо - в джаваскрипте наоборот всё именно так и обстоит, никаких проблем написать:
Используется синтаксис Javascript
function getGrandFathers( man )
{
    var maybeMan = MaybeMonad( man );
    mother = maybeMan.bind( getMother );
    gf1 = mother.bind( getFather );
    father = maybeMan.bind( getFather );
    gf2 = father.binf( getFather );
    return { gf1, gf2 };
};
 

нет. Это здесь даже естественно. Это "перевранный" другой пример из другой статьи...

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 20:47 
Заслуженный участник


27/04/09
28128
aa_dav в сообщении #1025775 писал(а):
А вот можно пример что потом по идее должно хотеться этим правильно воспользоваться?
Ну вот есть монада-список
Используется синтаксис Haskell
instance Monad [] where
  // с сохранением семантики упрощено относительно реального кода
  return :: a -> [a]
  return x = [x]
  // возвращаем список из указанной альтернативы
  (>>=) :: [a] -> (a -> [b]) -> [b]
  xs >>= f = concat (map f xs)
  // применяем ко всем альтернативам функцию, возвращающую список,
  // и соединяем их в один список

example n = do
  a <- [1..n]
  b <- [1..a]
  [(a, b), (b, a)]
// example 3 = [(1,1),(1,1),(2,1),(1,2),(2,2),(2,2),(3,1),(1,3),(3,2),(2,3),(3,3),(3,3)]
Эквивалентный код примера без do:
Используется синтаксис Haskell
example n =
  [1..n] >>= (\a ->
    [1..a] >>= (\b ->
      [(a, b), (b, a)]))
Напишете аналогичное с вашими «улучшениями»?

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 20:58 


11/12/14
893
arseniiv в сообщении #1025786 писал(а):
Из неё нельзя вытащить «единственное» значение


Ну так просто её значение это собственно список (массив в терминах JavaScript).
Весь смысл в том что делает bind - как написано собственно в комментариях он возьмёт функцию, которая должна возвращать списки, применит ко всех значением я соединим в один список.
Тут я только в примерах честно говоря теряюсь, было m a, а стало [a], не очень понятно... я до такого не доходил...

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 21:17 


05/09/12
2587
Используется синтаксис Lisp
(defn return (x) (cons x nil))
(defn bind (l f) (concat (map f l)))

(defn example (n)
    (bind (list-from-to 1 n)
          (lambda (a) (bind (list-from-to 1 a)
                            (lambda (b) (cons (cons a b) (cons (cons b a) nil)))))))
(printLn (example 3))

Код:
((1 1) (1 1) (2 1) (1 2) (2 2) (2 2) (3 1) (1 3) (3 2) (2 3) (3 3) (3 3))

На лискрипте. Имхо, весь смысл в том, как трактуется bind применительно к данным типам.

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 21:39 


11/12/14
893
Если предыдущий пост адресовался мне - то то, что код комбинирует списки это то понятно.
Мне непонятно где в коде хаскелля возникли и как монады (убивает например генератор [1..a], ведь если я (не)правильно понимаю Monad [] заставляет [] генерировать монаду списка, а что такое генератор списка от 1 и до монады мне вообще непонятно, всё, стоп машина мозговая) чтобы попытаться их воспроизвести в синтаксисе яваскрипта.

-- 10.06.2015, 22:48 --

Ааааа, врубился, генератор это блин функция скармливаемая монаде.
Ну млин хаскель, ну млин, растудыть твою туды...
Так, кажется догнал, сейчас воспроизведу...

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 21:49 


05/09/12
2587
aa_dav, пост скорее просто в качестве ответа arseniiv на его вопрос (хоть и не мне). Я сам не понимаю концепцию монад, да и функторов тоже, не говоря уже о тысяче разнообразных морфизмов, и хотел бы тоже приобщиться к знанию ,почитать умных людей, разобраться. Тем более что это первая интересная мне тема на форуме за несколько месяцев.

ЗЫ а вы все усложняете. m a и [a] это в контексте монады списка одно и то же. И генерирует монаду, насколько я знаю, реализация для данного контекста двух функций: bind и return. Конечно в каждой монаде они будут значить свое, в монаде списка мы уже написали что именно. В других монадах - другое. Более того, даже монаду списка можно не единственным образом определить, как и функтор - это только наши условности, лишь бы выполнялись законы монад и функторов. И никаких тут генераторов списка от 1 до монад нет, просто обычные генераторы списка от числа до числа - смотрите мой код на лискрипте, просто к этим сгенерированным спискам применяется функция.

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 22:33 
Заслуженный участник


27/04/09
28128
aa_dav в сообщении #1025794 писал(а):
Весь смысл в том что делает bind - как написано собственно в комментариях он возьмёт функцию, которая должна возвращать списки, применит ко всех значением я соединим в один список.
Тут я только в примерах честно говоря теряюсь, было m a, а стало [a], не очень понятно... я до такого не доходил...
Разумеется, тут смысл в bind, т. к. в моём примере только он и в ходу. :-) А вот m a здесь это как раз и есть [a], что можно записать более формально (язык поддерживает) как [] a — в других языках это могло бы писаться List a, m = List. Видели параметризованные типы (а по-русски — generics) — вот монадами как раз могут быть только типы от одного параметра.

В хаскеле это, кстати, выразимо с помощью kinds — обычные типы имеют кинд *, а тип с параметром кинда k1, в результате применения которого получается тип кинда k2, имеет кинд k1 -> k2 — кинды для типов то же, что типы для значений. В некоторых языках идут дальше и определяют обобщение для всех натуральных, но хаскель ограничивается тремя уровнями. Так вот, с помощью некоторого расширения GHC можно было бы заголовок описания класса монады записать как class Monad (m :: * -> *), явно указывая кинд, хотя обычно компилятор сам догадывается, потому что в функциях встречается только m a.

[m..n], как уже сказал _Ivana, это просто выражение типа [a], если m, n :: Enum a => a, т. е. типа, значения которого можно один за другим перечислять (а также через заданный шаг, для чего есть сахар [m1,m2..n] и ещё два сахара [m..] и [m1,m2..] для бесконечных списков. Всё это синонимы вызовов некоторых методов Enum, хотя тут для нас важно, что Enum Int, и тип упомянутых выражений, соответственно, будет [Int].

Ещё вижу кое-какую путаницу в основах, так что попробую их перечислить.
aa_dav в сообщении #1025802 писал(а):
ведь если я (не)правильно понимаю Monad [] заставляет [] генерировать монаду списка, а что такое генератор списка от 1 и до монады мне вообще непонятно, всё, стоп машина мозговая
Monad, как и любой класс в хаскеле, скорее, аналогичен интерфейсам языков с ООП — он описывает протокол, которому может удовлетворять какой-то набор типов (в частном случае, который у нас здесь, и который только и был в стандарте Haskell98, один тип; недавно в GHC появилось расширение, позволяющее нульарные классы, которым тоже находится применение). Чтобы указать, как и какой ещё набор удовлетворяет классу, пишется инстанс — в данном случае Monad [] с определениями методов (не обязательно всех, т. к. могут быть определения по умолчанию, что сближает классы не просто с интерфейсами из ООП, а с примесями (mixins); так себя ведут интерфейсы Ceylon, например).

Имея на руках класс и набор инстансов из подключенных модулей, компилятор может заменить метод класса типа Monad m => t m конкретным методом типа t [] или там t Maybe {здесь, кстати, t не просто сокращение какого-то неизвестного выражения, но ещё и :: (* -> *) -> *, но это уже можно счесть издевательством с моей стороны, так что скобки фигурные, и могли бы и не читать их} — во время ли выполнения или, при удаче (если программист достаточное количество конкретных типов прописал в других местах, обычно описывающих конкретные вещи), на этапе компиляции. Так что Monad [] не «заставляет [] генерировать монаду списка», тело инстанса Monad [] описывает, как понимать список как монаду.

Некоторые люди считают всё-таки [a] смущающим вариантом List a (хотя я не соглашусь — если все смущающие совпадения удалить, получится непривычный мне вариант языка, так что невзвешенная оценка вполне уместна). В их варианте было бы
Используется синтаксис Haskell
instance Monad List
  return :: a -> List a
  (>>=) :: List a -> (a -> List b) -> List b
и не было бы путаницы скобок с уровня значений со скобками с уровня типов (или нашлось бы что-то ещё не устраивающее).

А, и ещё: штучки вида Class params или (C1 ps1, C2 ps2, …) называются ограничениями (constraints) и могут пониматься как истинностные значения, знания о которых к нам приходят из и только из инстансов — либо в виде конкретных, в терминологии Пролога, фактов C ps, либо в виде более изощрённых выводимостей (C1 ps1, C2 ps2, …) => Cn psn, позволяющих в лучшем случае генерировать инстансы автоматически (а в худшем позволяющих компилятору завернуть ваш код, потому что это галиматья, и даже с расширениями иногда всё равно галиматья :roll: ). Соответственно, тип Constraints => t состоит из тех же значений, что и t, но только тех, для которых верны Constraints. (КО приглашён на случай, если я переоценил чьи-то знания.)

-- Чт июн 11, 2015 00:34:47 --

(Надеюсь, это что-то кому-то пояснило, а то я не уверен, что методически корректен.)

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 22:43 


11/12/14
893
Такс, да, догнал в чём тут подвох. Параметры то это параметры, вон оно чё Михалыч, это не эквивалентно тому что я писал с a = monad.bind... a это не монада же получается, а её параметр. Вон оно чё. Хитро получается. Дейсвительно так сразу и не соображу как это разумно перевести в яваскрипт. Надо всё в лямбды заворачивать до потрохов... И bind неоткуда и некуда приткнуть.
Да, тут имитация .bind лажает на корню.
Ладно, на сегодня хватит. :)

-- 10.06.2015, 23:50 --

arseniiv в сообщении #1025833 писал(а):
Некоторые люди считают всё-таки [a] смущающим вариантом List a


Я слаб в хаскелле, поэтому любая непривычно встреченная закорючка сразу же обрубает наглухо понимание.
В принципе достаточно было здесь только это и сказать - что [a] это извращенная форма List a.
И что генератор - тоже функция. :)

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 23:25 
Заслуженный участник


27/04/09
28128
Генератор как раз не функция, а выражение. Функции — это четыре сестрицы enumFrom[Then][To], которые в Enum и определяются (и [m..n] ≡ enumFromTo m n). Не хотел их явно называть, чтобы не запутывать ещё дальше. Так вот, в синтаксисе do слева от <- стоит переменная или другой шаблон (ага!) типа a, а справа — выражение типа m a, либо всю строку занимает выражение типа m a, либо там стоит let v = expr, где выражение уже типа a как и переменная — это чтобы не писать v <- return expr попусту.

aa_dav в сообщении #1025837 писал(а):
Ладно, на сегодня хватит. :)
Короче, непрочь буду увидеть, что как-нибудь у вас получится со списками. Просто, видимо, в следующем заходе вернитесь к «не улучшенной» версии из статьи про Python. :-)

-- Чт июн 11, 2015 01:26:22 --

(Оффтоп)

arseniiv в сообщении #1025858 писал(а):
непрочь буду увидеть
(И коварно предложу ещё какую монаду пострашнее! :mrgreen: )

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 23:40 


11/12/14
893
Аааааа... Мда.... Получилось в рамках "улучшенного" подхода, когда глубже проняло в чём подвох.
АДСКИ, АДСКИ вышло. :)))))

Если вкратце, то:

код: [ скачать ] [ спрятать ]
Используется синтаксис Javascript
function genarray( high )
{
        low = 1;
        var res = [];
        var i;
        for ( i = low; i <= high; i++ )
                res.push( i );
        return res;
};

function ListMonad( value )
{
        this.value = value;
        this.bind = function( func )
        {
                var res = [];
                var i, j;
                for ( i = 0; i < value.length; i++ )
                {
                        var suba = func( value[ i ] );
                        for ( j = 0; j < suba.length; j++ )
                        {
                                res.push( suba[ j ] );
                        };
                };
                return new ListMonad( res );
        };     
};

function example2( n )
{
        return new ListMonad( genarray( n ) ).bind( function ( a ) { return new ListMonad( genarray( a ) ).bind( function ( b ) { return [[a,b], [b,a]] } ).value } ).value;
};

x = example2( 3 );
WScript.Echo( "x: " + x );
for ( i = 0; i < x.length; i++ )
{
        WScript.Echo( "x[" + i + "] = " + x[i] );
};
 


вывод:
Код:
x[0] = 1,1
x[1] = 1,1
x[2] = 2,1
x[3] = 1,2
x[4] = 2,2
x[5] = 2,2
x[6] = 3,1
x[7] = 1,3
x[8] = 3,2
x[9] = 2,3
x[10] = 3,3
x[11] = 3,3


Но это конечно ни в борщ ни в красную армию. Смысла, конечно, никакого...

 Профиль  
                  
 
 Re: Mонады в javascript
Сообщение10.06.2015, 23:46 
Заслуженный участник


27/04/09
28128
(Пока писал, вы уже выложили свой вариант, но оставлю как reference implementation. :-) )

Эх, если бы в JS были бы макросы, была бы возможность и что-то do-подобное устроить. А так оно будет громоздкущим:
Используется синтаксис Javascript
// все имена условны
// range(1, n) = [1, …, n]
// предполагается, что bind и не используемый здесь return добавили в Array.prototype
function example(n) {
  return range(1, n).bind(function(a) {
    return range(1, a).bind(function(b) {
      return [[a, b], [b, a]];
    }
  }
}
 

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 43 ]  На страницу Пред.  1, 2, 3  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group