2014 dxdy logo

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

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




На страницу Пред.  1, 2, 3
 
 Re: Mонады в javascript
Сообщение10.06.2015, 23:50 
arseniiv в сообщении #1025858 писал(а):
Просто, видимо, в следующем заходе вернитесь к «не улучшенной» версии из статьи про Python.


В "не улучшенной" версии я вынужден под каждую монаду писать свой набор функций с ней работающий. Или пропихивать в каждую такую функцию конструктор монады. Тоже можно рассмотреть как вариант, но в целом как то тоже не очень.
P.P.S.
Да, вот вы выложили свой вариант - он короче именно потому что range это специальная функция уже возвращающая монаду. У меня сложнее именно на то, что нужная монада создаётся по месту, а genarray обычная функция, ничего о монадах не знающая, как параметр.

 
 
 
 Re: Mонады в javascript
Сообщение10.06.2015, 23:51 
arseniiv в сообщении #1025868 писал(а):
Эх, если бы в JS были бы макросы

Используется синтаксис Lisp
(defn return (x) (cons x nil))
(defn bind (l f) (concat (map f l)))
(def <- (macro (_n _v _e) (bind _v (lambda (_n) _e))))

(defn do-example (n)
    (<- a (list-from-to 1 n)
    (<- b (list-from-to 1 a)
    (cons (cons a b) (cons (cons b a) nil)) )))
(printLn (do-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))

 
 
 
 Re: Mонады в javascript
Сообщение10.06.2015, 23:52 
arseniiv в сообщении #1025868 писал(а):
предполагается, что bind и не используемый здесь return добавили в Array.prototype


А, даже хитрее. Тогда монады, как отдельного класса и нет, есть просто массив с обновлёнными методами. Ну тоже хлеб интересный.

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 00:08 
Кстати говоря, некоторые монады позволяют прервать вычисления — например, та же Maybe с помощью внедрения пустого значения, или монада ошибки, которая вместо пустого значения имеет какую-то информацию и т. д.. Для них используется класс
Используется синтаксис Haskell
class Monad m => MonadZero m where
  mzero :: m a
  // должно выполняться mzero >>= k = mzero

Для прерывания вычислений вставляется mzero, после чего дальше всё >>=е пропускается благодаря лени (раз второй аргумент не нужен, не будем вычислять — и тут в JS может получиться упс в некоторых случаях (если только не реализовать force/delay, запутывая всё окончательно; и, опять же, нет макросов для определения delay)). Для улучшения этого есть функция
Используется синтаксис Haskell
guard :: MonadZero m => Bool -> m ()
guard False = mzero
guard True = return ()
использующаяся, например, так:
Используется синтаксис Haskell
filteredPairs :: [Name] -> [Fruit] -> (Fruit -> Bool) -> (Name -> Fruit -> Bool) -> [(Name, Fruit)]
filteredPairs names fruits isEdible likes = do
  fruit <- fruits
  guard (isEdible fruit)
  name <- names
  guard (likes name fruit)
  return (name, fruit)

Пример немного искуственный и может быть заменён в этом случае на list comprehension, раз уж тут снова список-монада.

aa_dav в сообщении #1025871 писал(а):
А, даже хитрее. Тогда монады, как отдельного класса и нет, есть просто массив с обновлёнными методами. Ну тоже хлеб интересный.
Именно. В смысле ООП это скорее интерфейс, как я выше говорил. :-) А классы и другие типы могут быть только инстансами её. Т. к. JS динамический по части интерфейсов, его как бы и не надо нигде писать, только молясь о правильном понимании слов bind и return инстансописателем.

aa_dav в сообщении #1025869 писал(а):
Да, вот вы выложили свой вариант - он короче именно потому что range это специальная функция уже возвращающая монаду.
Но так и должно быть. Опять же, как я уже писал, справа от стрелочки выражение типа m a.

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 00:14 
Аватара пользователя
Скажите, а где на практике это можно практично применить??

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 00:24 
Да, теперь уложилось понимание.
В хаскелле bind просто и тупо смотрит на свои аргументы и срабатывает для инстанса, но главное что левый аргумент может быть не самим инстансом - а то что там в аргументах замучено. Действительно скорее миксины, чем какие то классы. И тут перегрузка прототипа в яваскрипте очень удачно сыграло.
С другой стороны неимение такого механизма просто заставляет нас в яваскрипте bind пристёгивать как метод... к тому что было левым аргументом в хаскеле.
И таким образом первая функция возвращающая монадический тип начинает "раскручивать" последовательность вызовов.

Такс, и поглядев еще раз на примеры монад Хаскеля вижу что там как раз предполагается что функция вернет монаду. Значит видимо вот оно и есть - функции работающие с монадами должны возвращать монады. Уже припоминаю что есть вроде как обёртки. Тогда да, первичный пайтоновский вариант лучше соответствует тому что в хаскелле происходит - это был не баг, как я подумал, а фича.

-- 11.06.2015, 01:24 --

Geen в сообщении #1025884 писал(а):
Скажите, а где на практике это можно практично применить??


В Хаскелле. В яваскрипте не нужно. Я лично в теме участвую исключительно для улучшения понимания.

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 00:32 
Аватара пользователя
aa_dav в сообщении #1025892 писал(а):
В яваскрипте не нужно.

Гм, а это, часом, не оффтоп тогда? :-)

-- 11.06.2015, 00:35 --

Я не занудствую, я просто что-нибудь рациональное пытаюсь найти :-)

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 02:08 
Geen в сообщении #1025884 писал(а):
Скажите, а где на практике это можно практично применить??
Здесь монады ушли недалеко от строк или каких-нибудь контейнеров: где угодно, это строительный материал. В данном случае обычно для «строительства» логики. Можно удариться в детали по каждой из монад, если хотите (но я про все не расскажу). Потом, ещё стрелки есть со своим сахаром и комонады с пока не реализованным предложенным сахаром, и просто аппликативные функторы, которые и без сахара нормально выглядят, и… и…

aa_dav в сообщении #1025892 писал(а):
Да, теперь уложилось понимание.
В хаскелле bind просто и тупо смотрит на свои аргументы и срабатывает для инстанса, но главное что левый аргумент может быть не самим инстансом - а то что там в аргументах замучено.
Видать, не совсем ещё уложилось. :wink: Тут инстансом будет ненаселённый (нет значений) тип [] List, потому что кинд его не * , а * -> *. Т. е. левый аргумент не то что может быть не инстансом, он даже не будет им никогда, а будет результатом применения к List какого-то *-типа. (Ну и иногда инстансы — это наборы нескольких типов, так что так говорить стоит с осторожностью, хотя я первый начал.)

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 06:22 
Geen в сообщении #1025899 писал(а):
Гм, а это, часом, не оффтоп тогда?


Тема называется "монады в яваскрипт". =) О каком оффтопе речь? =)
Рациональное зерно тоже есть - иногда императивному программисту хочется хотя бы глазком увидеть - что там за монады все обсуждают в темах про ФЯ - тут можно хотя бы примерно понять в чём суть, хотя, опять таки, без хаскелля оно и не нужно в реальном коде на том же яваскрипте.

arseniiv в сообщении #1025931 писал(а):
Видать, не совсем ещё уложилось.


Ну я некорректно выразился. У меня ранее много непонимания было как раз потому что я думал, что тип монады он как какой то класс (поэтому пытался увидеть как генератор списка куда то утягивается внутрь монады чтобы породить именно типа эээ... "Monade[a]". А на деле совсем по другому, да.

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 09:36 
Охотно верю, что ситуация улучшилась ещё тогда, просто решил доиграть в корректность. :-)

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 09:59 
Сошёл с ума и реализовал пример с List на C++. %)
Самое интересное что в С++ operator>>= можно так сказать перегрузить для того же vector типа "неинтрузивно", что оно не затрагивает сам тип vector...
Но невозможность вывести тип на ходу заставляет вменять тип по месту использования и получается еще большая жуть. =)

код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#include <iostream>
#include <vector>
#include <functional>

template< class T, class U >
std::vector<U> operator>>=( std::vector<T> val, std::function<std::vector<U>(T)> f )
{
        std::vector<U> res;
        for( auto x: val )
        {
                std::vector<U> subs = f( x );
                for ( auto y: subs )
                {
                        res.push_back( y );
                };
        };
        return res;
};

std::vector<int> genarray( int n )
{
        std::vector<int> res;
        for ( int i = 1; i <= n; i++ )
                res.push_back( i );
        return res;
};

template< class T >
struct mpair
{
        T a, b;
        mpair( T na, T nb ): a(na), b(nb) {};
};
               
std::vector<mpair<int>> example( int n )
{
        return genarray( n ) >>= std::function<std::vector<mpair<int>>(int)>( [&](int a){ return genarray(a) >>= std::function<std::vector<mpair<int>>(int)>([&](int b) { return std::vector<mpair<int>>{ mpair<int>(a,b), mpair<int>(b,a) }; } ); } );
};

int main()
{
        auto r = example( 3 );
        for ( auto x: r )
                std::cout << "(" << x.a << "," << x.b << ")";
};
 


Но таки да, работает: http://ideone.com/THHT0i

 
 
 
 Re: Mонады в javascript
Сообщение11.06.2015, 23:41 
Ну раз уж с С++ не оффтоп, то я со своим лискриптом снова влезу - подсыпал еще немного макросового сахара в do-нотацию а-ля хаскель:
код: [ скачать ] [ спрятать ]
Используется синтаксис Lisp
(defn return (x) (cons x nil))
(defn bind (l f) (concat (map f l)))
 
(defn foldapp (l)
    (cond (null? (car (cdr l))) (car l)
          (append (deinfix (take 3 l)) (cons (foldapp (drop 3 l)) nil)) ))
 
(defn deinfix (l) (cons (car (cdr l)) (cons (car l) (cdr (cdr l)))) )
 
(def do (macro (_l) (eval (foldapp '_l))))
 
(def <- (macro (_n _v _e) (bind _v (lambda (_n) _e))))
 
(defn do-example (n) (do (
    a <- (list-from-to 1 n)
    b <- (list-from-to 1 a)
    c <- (list-from-to 1 b)
    (cons (cons c (cons b a)) nil)
)))
(printLn (do-example 3))
 
((1 1 1) (1 1 2) (1 2 2) (2 2 2) (1 1 3) (1 2 3) (2 2 3) (1 3 3) (2 3 3) (3 3 3))
 

 
 
 
 Re: Mонады в javascript
Сообщение12.06.2015, 08:28 
P.S.
Напомнили на другом форуме что как раз для подобных случаев в С++11 добавили delctype. Код тогда становится много более вменяемым:
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
template< class T, class F >
auto operator>>=( std::vector<T> val, F f )->decltype( f(val[0]) )
{
  decltype( f(val[0]) ) res;
  for( auto x: val )
  {
    decltype( f(val[0]) ) subs = f( x );
    for ( auto y: subs )
    {
      res.push_back( y );
    };
  };
  return res;
};

std::vector<mpair<int>> example( int n )
{
  return genarray( n ) >>= [&](int a){ return genarray(a) >>= [&](int b) { return std::vector<mpair<int>>{ mpair<int>(a,b), mpair<int>(b,a) }; }; };
};
 

 
 
 [ Сообщений: 43 ]  На страницу Пред.  1, 2, 3


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group