Специализни шаблонца!

Previous Entry Поделиться Next Entry
Про динамику и статику
Vash
udpn
Только что решил одну простую задачу на Python и Haskell с целью сравнения динамической и статической типизации в функциональных языках. Есть последовательность чисел, в которой сначала один раз записывается единица, два раза двойка и так далее. Нужно получить первые N элементов этой последовательности.


  1. import Data.List

  2. main = interact $ intercalate " " . map show . flip take (concat $ map (\x -> replicate x x) [1..]) . read



  1. from itertools import *

  2. print(' '.join(islice(chain.from_iterable(map((lambda x: repeat(str(x), x)), count())), 0, int(input()))))


(EDIT. Для C++ oneliner тоже приведу, конечно.)


  1. #include <iostream>

  2. int main() { int N; std::cin >> N; if (N--) std::cout << '1'; for (int i = 2; ; ++i) { for (int j = 0; j < i; ++j) { if (!N--) return 0; std::cout << ' ' << i; } } }


Если присмотреться, то станет заметно, что на Python решение получилось на 7 символов длиннее. Учитывая, что авторам Python для этого пришлось прыгать через хулахуп, придумывая новые названия функциям над генераторами, и что найти нужную функцию уже не так просто, я закрываю в своём ЖЖ тему о динамической типизации раз и навсегда. Удачного дня.
Метки:

  • 1
А теперь отдаем этот код на поддержку в бангалор.

Промежуточные именованые сущности я поудалял для чистоты эксперимента. Императивно этот код вообще отвратный, так что бангалурцы не осилят в любом случае. Пополню-ка пост описанием задачи.

Я правильно понял идею?

lang=#cs
stdin.read (c)-> ([1..c].map (x)-> ([1..x].map ()-> x).join " ").join " "
 

Re: Я правильно понял идею?

1) Я так и не понял, что это за язык
2) Наверное, нужно обновить решение, так должно выйти короче

тем более, что хаскель можно ещё укоротить. В связи с тем, что список - функтор, show можно перенести аж к replicate (питон так и делает), а concatMap можно заменить на list comprehension.

Нуу, для полноты картины не хватает примера на функциональном типизированном CBV-языке.

А любителям СBV-языков - эмуляции кода на х-е через defer/force

Хотел пошутить, что знаю одного автора функционального типизированного CBV языка, спрошу у него, но после чтения доков по HNC как-то разуверился

Edited at 2014-11-20 19:13 (UTC)

Удачного дня

for x in range(int(input())): (print(x, sep=' ', end=' ') for i in range(x))

RE: Удачного дня

И без всяких импортов :)

Я тут что, единственный, кому кажется, что эти примеры ничего осмысленного не иллюстрируют?

Написание однолинеек - довольно глупое занятие на любом языке (даже на Хаскелле).
Каких-либо реальных достоинств или недостатков статической типизации в сравнении с динамической и наоборот на однолинейках не проявляется.
Например, типичные ошибки вида "там поменяли, тут не поменяли" или "забыли, как называется".

я тоже сперва тупил, а потом увидел тег "юмор"

interact $ unwords . flip take (concatMap (\x -> replicate x (show x)) [1..]) . read

Edited at 2014-11-20 19:24 (UTC)

А цветовая гамма вон насколько у статических лучше. Только у динамического питона в этом посте уродливый оранжевый болд! Статика рулит.

Правильно, нечего тут вырвиглазными цветами код красить.

Жырнота... :)

При том, что читаемое решение на обоих языках выглядит почти одинаково (do с монадой списков в Haskell и такой же for+for+yield в Python).

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

sequence!"n".map!(a => repeat(a,a)).joiner.take(readln.strip.to!int).writeln;

Прямо в шелле:
C:\>rdmd --eval="sequence!`n`.map!(a => repeat(a,a)).joiner.take(readln.strip.to!int).writeln;"
20
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6]



Edited at 2014-11-21 12:22 (UTC)

> sequence!"n".map!(a => repeat(a,a)).joiner.take(readln.strip.to!int).writeln;

т.е. эта штука работает через выхлоп в строку и затем ее парсинг?

если так, то динамическая типизация налицо

между тем, это вариант мне кажется более читабельным, чем остальные потоковые варианты (и да, я не сторонник динамической типизации, я бывший ext_956459, см. чуть ниже)

и еще -- вроде нужно же выводить не через запятую, а через пробел, так что тут надо добавить кода

Edited at 2015-01-11 06:31 (UTC)

Юмор юмором, а мне вот нравится вариант через ap take repeat =<< [1..]

Ну тогда import Control.Monad же ещё нужен. Я вообще ap не люблю, <*> всяко ближе. Но вообще две монадки так плотно использовать это да, мощно.

Edit: оно?

import Control.Monad
main = interact $ unwords . flip take (map show . ap take repeat =<< [1..]) . read

Edited at 2014-11-28 14:40 (UTC)

начнем с того, что я не новый юзер, а ext_956459 (который во френдах udpn); говногугль, похоже, отключил у меня openID-авторизацию, похоже потому, что у меня в акке не имя и фамилия, а буквы -- во всяком случае залогинися в lj как раньше я не могу, и посему сделал такой акк: M_E_again

понятно, что верить этому не обязательно (хотя, впрочем, в будущем я думаю это доказать, откопав в кэше какие-нибудь страницы "только для френдов") -- смысл этого в том, что я иногда перечитываю старые дискуссии, а скачивалку их целиком под логином все еще поленился сделать

теперь же к теме: вполне ожидаемо, это будет с++

на те однострочники на с++, которые приведены, нельзя смотреть без слез

вот мои варианты:
int main(){ int N,A,a; std::cin>>N; for(A=1; N; ++A) for(a=A; N&&a; --a) std::cout<<A<<(--N?" ":""); }
можно чуть подлиннее, если переменные А и а объявлять в цикле:
int main(){ int N; std::cin>>N; for(int A=1; N; ++A) for(int a=A; N&&a; --a) std::cout<<A<<(--N?" ":""); }
а вот чуть покороче, в стиле перла:
int main(){ int N; std::cin>>N; for(int A=1,a=A; N; --a||(a=++A)) std::cout<<A<<(--N?" ":""); }
а вот с более осмысленными названиями (хотя вопрос, улучшается ли читабельность от длинных слов)
int main(){ int overall_count; std::cin>>overall_count; for(int item=1; overall_count; ++item) for(int item_count=item; overall_count&&item_count; --item_count) std::cout<<item<<(--overall_count?" ":""); }
и главный вопрос: являются ли (более короткие, да) проги в стиле потоковой обработки более читабельными? мне кажется, что в этой задаче императивный код все же более читабелен (и писабелен, кстати), будучи нормально отформатирован:
int main()
{
    int overall_count;
    std::cin >> overall_count; 
    for( int item=1; overall_count; ++item )
        for( int item_count=item; overall_count>0 && item_count>0; --item_count )
            std::cout << item << ( --overall_count ? " " : "" ); 
}
еще насчет читабельности: даже в однострочнике можно выбирать осмысленные названия переменных -- не i&j, а a&A; осмысленность в том, что а маленькое меняется от А большого до 0, т.е. а маленькое всегда меньше А большого


Edited at 2015-01-11 07:13 (UTC)

Ну вот мне кажется, что лучше вместо a и A использовать k и n, потому что в матане 1 <= k <= n.

а еще есть вопрос, как этот однострочник *должен* выглядеть на приличном языке; я думаю как-то так:
iota<1,inf> I;
list(I).replicate(I).flatten().take(read<int>()).join(' ').print();
c поправкой на то, что синтаксис с++ несколько коряв, можно и лучше

(iota должна быть объявлена отдельно, т.к. list(iota<1,inf>).replicate(iota<1,inf>) даст то, что соответствует 2 вложенным циклам, а не 1-му, т.к. iot-ы независимы?)


Edited at 2015-01-11 07:09 (UTC)

Clojure:

(->> (range) (map #(repeat % %)) (apply concat) (take (read)) (apply print))

  • 1
?

Log in

No account? Create an account