LINUX.ORG.RU

Да это говно какое-то. Я прочитал полторы книжки по хаскеллю, написал два хеллоуворлда, один физзбазз и четыре факториала и просто так не понимаю, что делает этот код, а гуглить и вдумываться не хочу, но предположу, что он берет фильтр от мапа.

hlebushek ★★ ()

берёшь такой ghci

вводишь туда

λ> :t (. map) . (.) . filter
(. map) . (.) . filter :: (b -> Bool) -> (a -> b) -> [a] -> [b]

и всё понимаешь

f1u77y ★★★ ()

Нет, не читаем. Сам написал или это выдача лямбдабота?

KblCb ★★★★★ ()
Ответ на: комментарий от qnikst

лично я с первого взгляда не понял. а если я не понимаю с первого взгляда, толезу в ghci, ибо так быстрее

f1u77y ★★★ ()
Ответ на: комментарий от x3al

То есть, то что в нормальных языках и так есть искаропки, в хаскеле требует костылей и особой магии, правильно я понял?

somequest ()

Выдача unpl - (\ g m d -> filter g (map m d)) - намного понятнее кода в оп-посте.

hlebushek ★★ ()
Ответ на: комментарий от somequest
function(cond, func, collection) {
  return filter(cond, map(func, collection));
}

Это длиннее, чем в ОП. Твой код неэквивалентен, поскольку нужна функция. Теперь брысь.

x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

Приведенный твой код понятнее как минимум из-за того, что названия аргументов служат комментариями и объясняют почти все, что нужно. Ну и вообще такой point-free, как у ТСа, слишком сложно читается.

hlebushek ★★ ()
Ответ на: комментарий от f1u77y

Чтобы понять целое, нужно понять его части. А вот такие штуки нифига не понятны:

Prelude> :t (. map)
(. map) :: (([a] -> [b]) -> c) -> (a -> b) -> c

Prelude> :t (.) . filter
(.) . filter :: (a1 -> Bool) -> (a -> [a1]) -> a -> [a1]

iVS ★★★★★ ()

а как это выглядит на Go?

kep ()
Ответ на: комментарий от qnikst

Да дело не в точности аналога, а в том, что в хаскеле делается через жопу, то что в нормальных ООП языках делается напрямую. Ясно, что любой код можно записать в стиле передачи сообщений, если проектировать правильно.

somequest ()
Ответ на: комментарий от iVS

А вот такие штуки нифига не понятны:

pointful помогает:

$ pointful "(. map)"
(\ a d -> a (map d))

$ pointful "(.) . filter"
(\ f b c -> filter f (b c))
monk ★★★★★ ()
Ответ на: комментарий от somequest

То есть, ты просто пишешь кучу скобья и лишних явных аргументов, только ради того, чтобы не писать в ООП-стиле.

filter(cond, map(func, collection))
collection.map(func).filter(cond)

Скобок ровно столько же, разница в двух запятых в обмен на проблемы — нет, нафиг такой ООП, лучше стащить map и filter из Ramda.

И нет, я не юзаю point-free когда оно доходит до композиции композиции: мне же это читать.

x3al ★★★★★ ()
Ответ на: комментарий от somequest

то что в нормальных ООП языках делается напрямую

Ну да, например на http://rosettacode.org/wiki/Reverse_words_in_a_string

В «нормальном ООП» C++

#include <algorithm>
#include <functional>
#include <string>
#include <iostream>
#include <vector>
 
//code for a C++11 compliant compiler
template <class BidirectionalIterator, class T>
void block_reverse_cpp11(BidirectionalIterator first, BidirectionalIterator last, T const& separator) {
   std::reverse(first, last);
   auto block_last = first;
   do {
      using std::placeholders::_1;
      auto block_first = std::find_if_not(block_last, last, 
         std::bind(std::equal_to<T>(),_1, separator));
      block_last = std::find(block_first, last, separator);
      std::reverse(block_first, block_last);
   } while(block_last != last);
}
  
int main() {
   std::string str1[] = 
    {
        "---------- Ice and Fire ------------",
        "",
        "fire, in end will world the say Some",
        "ice. in say Some",
        "desire of tasted I've what From",
        "fire. favor who those with hold I",
        "",
        "... elided paragraph last ...",
        "",
        "Frost Robert -----------------------"
    };
 
   std::for_each(begin(str1), end(str1), [](std::string& s){
      block_reverse_cpp11(begin(s), end(s), ' ');
      std::cout << s << std::endl;
   });
  
   return 0;
}

А в страшном и непонятном Haskell:

revstr :: String -> String
revstr = unwords . reverse . words -- point-free style
--equivalent:
--revstr s = unwords (reverse (words s))
 
revtext :: String -> String
revtext = unlines . map revstr . lines -- applies revstr to each line independently
 
test = revtext "---------- Ice and Fire ------------\n\
        \\n\
        \fire, in end will world the say Some\n\
        \ice. in say Some\n\
        \desire of tasted I've what From\n\
        \fire. favor who those with hold I\n\
        \\n\
        \... elided paragraph last ...\n\
        \\n\
        \Frost Robert -----------------------\n" --multiline string notation requires \ at end and start of lines, and \n to be manually input
monk ★★★★★ ()
Ответ на: комментарий от x3al

Скобок ровно столько же вложенность другая. Но ты не учитываешь насширяемость. В ООП стиле ты добавишь легко еще 100 методов в класс, и синтаксис не изменится. А в твоем случае надо будет полностью и реализацию переписывать, и в вызовах количества аргументов. То есть, переписывть весь код, короче.

somequest ()
Ответ на: комментарий от somequest

А что тебя заставляет из раза в раз тут регистрироваться и продолжать вещать одно и тоже?

qnikst ★★★★★ ()
Ответ на: комментарий от somequest

если проектировать правильно.

Ага. И каждый раз, как в действии участвуют больше одного типа, так сразу возникает проблема, чьё это действие (метод обязан принадлежать классу). То есть собака.вертеть(хвост) или хвост.вертеться_на(собака) или бог.вертеть(собака, хвост)? И если не угадал (когда-то намного позже понадобилось строить иерархию не на том типе объектов), то приходится всё переписывать заново.

monk ★★★★★ ()
Ответ на: комментарий от somequest

Да ну нафиг с тобой спорить. Когда выяснится, что оно же должно работать с другими десятью типами объектов — ты с радостью будешь добавлять эти 100 методов в каждый класс «чтобы не переписывать код». А где нужно переписывать код в безобъектном варианте — даже не покажешь.

x3al ★★★★★ ()
Ответ на: комментарий от somequest

В ООП стиле ты добавишь легко еще 100 методов в класс, и синтаксис не изменится. А в твоем случае надо будет полностью и реализацию переписывать

ЩИТО??? В не-ООП ты так же легко добавишь 100 функций в модуль. Или покажи пример, при котором ООП расширяется, а, например, Haskell — нет.

monk ★★★★★ ()
Ответ на: комментарий от monk

метод обязан принадлежать классу

вообще то не обязан, есть apply для этого

somequest ()
Ответ на: комментарий от somequest

LOL, кто сказал, что в плюсах есть ООП? Тем более *нормальное*.

Тогда какой в каком языке есть *нормальное* ООП? Simula? Smalltalk?

monk ★★★★★ ()
Ответ на: комментарий от monk

Щас пожру, потом покажу. Думаю, это легко показать. В принципе, об этом Стив Декорт нормально написал

A simple example: Apple's FoundationKit has a NSURLRequest object which can only be initialized with an initialized NSURL instance. NSURL can only be initialized with a URL string. The URL string in the NSURL cannot be changed after initialization and the NSURL cannot be changed after the NSURLRequest.

Now this is ok if you can assume you'll never need to change the URL after it's instantiated or change a NSURLRequest's url after it's instantiated. Unfortunately, these assumptions are wrong.

Consider an Amazon S3 request. Setting up the URL scheme, domain, path and parameters can involve logic specific to the S3 request. Naturally, we'd like something like an S3Request subclass of NSURLRequest that would contain this logic. But as our constructor effectively makes these things immutable by the instance, we can't.

So now we've got all this logic and data which should be handled by the request but can't be. So we can either do the wrong thing by creating giant constructor methods that try to pass in everything, and which invariably make their own false assumptions (e.g. that you'll never need to switch the url scheme from https to http for testing) or we can do the ugly thing by creating a new class that holds all the data which NSURLRequest does but is used to create a NSURLRequest request instance after all it's data is set.

The design decision to use constructors in these frameworks classes has the unseen consequence of limiting our design decisions to a choice between the wrong way or the ugly way and this isn't an isolated case. I've seen many other examples of this problem in the Java and C++ world but I suspect they are particularly common among FP languages which seem to actively encourage this pattern of design.

Final notes: It's not the use of a convenience constructor that is the problem, but that such uses are typically associated with the use of immutable instance state. Some might propose returning a new instance for each mutation as a solution, but this creates even worse code when you consider it potentially has to follow the entire immutable state chain and the consequences for multiple references.

somequest ()
Ответ на: комментарий от x3al

В ООП то как раз, напротив, нет ограничений на иерархию. можешь иметь супер-супер-супер тип/класс, так как не плодим лишних сущностей.

somequest ()
Ответ на: комментарий от Debasher

Как это ты позволил, психическому столько раз опускать себя в коде? Выходит, ты даже на болезного не тянешь?

somequest ()
Ответ на: комментарий от somequest

В ООП то как раз, напротив, нет ограничений на иерархию. можешь иметь супер-супер-супер тип/класс, так как не плодим лишних сущностей.

Нет, так нельзя. Иначе классовая иерархия будет бредовой.

Кроме того, как map, так и filter элементарно пишутся, если коллекции умеют внешнюю итерацию. Делать их методами — костыль для языков, не умеющих в надёжную внешнюю итерацию и в коллекции. Например, javascript'а.

x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 2)
Ответ на: комментарий от somequest

В принципе, об этом Стив Декорт нормально написал

Так он как раз про ООП и написал. Что предположения базового класса не позволяют от него нормально наследоваться (нет гибкости).

monk ★★★★★ ()
Ответ на: комментарий от x3al

Иначе классовая иерархия будет бредовой.

Не будет она бредовой. Это естественная вещь для ООП, просто не для рядового программиста, привыкшего к жабе.

somequest ()
Ответ на: комментарий от somequest

Ты слышал про интерфейсы?

Плюс ты не можешь каррировать метод .map/.filter, но можешь каррировать такие функции.

Ну и чем принципиально отличается map от, скажем, zip? Попробуй реализовать её методом — увидишь, почему это бред.

x3al ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.