Haskell: day 1.

Hosszas merlegeles utan ugy dontottem, hogy a Haskell lesz az elso tisztan funkcionalis nyelv, amit megtanulok. El is kezdtem olvasni a Learn You a Haskell for Great Good! cimu konyvet. A list comprehension cimu resznel tartottam, amikor eszembe jutottak a Project Euler kezdo problemai.

A legelso feladat a kovetkezo: adjuk ossze azokat szamokat 0 es 999 kozott, melyek oszthatok 3al vagy 5el.
Haskellben rem elegans a megoldas:


sum [x | x <- [0..999], x `mod` 3 == 0 || x `mod` 5 == 0 ]

Hozzászólások

A Mandelbrot-halmaz számítás/rajzolás is szép kódot eredményez.

Haskellesek szokták mondani - persze elfogultan -, hogy a helyes kód általában szép is.

Ismerve az előzményeket, nem bírom ki, hogy ne trollkodjam ide PHP-ben:


echo array_sum(array_filter(range(1,999), function($x) { return $x % 3 == 0 || $x % 5 == 0; } ));

:D

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Szerintem a Haskelles kóddal semmi baj nincs, teljesen érthető. Egyedul a 'mod' jelölése szokatlan. Amugy ha mar olvashatosag, akkor:

var x = Enumeration.Range(1, 999).Where(x => x % 3 == 0 || x % 5 == 0).Sum();
var y = (from x in Enjmeration.Range(1, 999) where x % e == 0 || x % 5 == 0 select x).Sum();

Vagy

[code]select sum(x)
from generate_series(1, 999) as x
where x % 3 = 0 or x % 5 = 0

De ez mind ugyanezt jelenti C#-ban (Postgre)SQL-ben vagy akar fenn PHP-ben, csak mas syntaxszal, mint a fenti Haskelles kod.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Benevezek én is a C++-szal :-) :

#include <iostream>
template <int N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
template <> struct Sum<0> { enum { value = 0 };};
int main(){int x = Sum<999>::value;std::cout<<x<<"\n"; return 0;}

Elismerem, az utolsó sor már nem tisztán funkcionális. Mea culpa.

yesod framework, snap framework jut eszembe. Yesoddal konnyebb elindulni, snappel tisztabb erzese van az embernek. A web fejlesztes is rengeteget tud profitalni haskellbol. Pl type safe routes: /user/edit/{UserId} ahol ha nem UserId tipust adsz at forditasi hiba.. De az "applicative forms" otlet is marha elegans.

Egyebkent magam részéről alkalmazasfejlesztesre ezert tartom jo nyelvnek a C#-ot. Alapvetoen imperativ oop nyelv, de vannak funkcionális elemei is, alapbol statikus, erosen típusos nyelv, de ha kell, ott a dynamic. Meg egy csomo jóság es a framework sem rossz mögötte.

Mondjuk a sorvegi pontosvesszoket felednem, illetve jo lenne, ha alapbol a referencia típusok non-nullablek lennenek, es az ertek tipusoknal levo Nullable vagy rövidített T? formában engednem a null erteket ahol lehet...

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Én pl. használom a Monot Androidon való fejlesztésre.
Teljesen jól működik. A csúcs az lenne, ha az Android plugin beépülne a VS-be, de ezt újabban már nem a VS korlátozza.

A .NET és a Mono már régóta közeledik egymáshoz, kölcsönösen osztanak meg libraryket, frameworköket, bővebben itt.

Fuszenecker Róbert

Mondjuk amióta Xamarinként ténykednek azért látható, hogy a saját pecsenyéjüket akarják sütögetni és a .NET kompatibilitás inkább egy szükséges rossz, mint cél. Persze, okok érthetőek.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Ezt én értem, viszont magam részéről azt szeretem a VS+.NET-ben, hogy kapok egy jó, kényelmes, integrált környezetet, platformot, ami ha tartogat is időnként fasságokat összességében messze jobb, mint bármi, amit eddig láttam :)

És azt szeretem a webfejlesztésben, hogy ...

...

...

... ja igazából rühellem a webfejlesztést úgy ahogy van. :D

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Clojure:


(->> (concat (range 0 1000 3) (range 0 1000 5))
     set
     (reduce +))

Fogjuk a 3-al es 5-el oszthato szamokat, bedobjuk egy setbe, majd osszeadjuk. Egyszeru es nagyszeru.

Hy:


(sum (list-comp x [x (range 0 1000)] 
                (or (= (% x 5) 0) 
                    (= (% x 3 ) 0))))

Vagy Clojure mintara:


(->> (+ (list (range 0 1000 3)) (list (range 0 1000 5)))
     set 
     (reduce (fn [x y] (+ x y))))

--
|8]

Korábban már egyszer nekikezdtem a Haskell tanulásának, de akkor szerencsére/sajnos (nem kívánt rész törlendő) nem volt rá elég időm, így felhagytam az ismerkedéssel. Most van egy kis szabadidőm, és a postod újra felkeltette az érdeklődésemet. Talán most tovább jutok.

Az általad is linkelt irodalom második fejezetének a végén (typeclasses), úgy gondoltam, hogy később ezt a fejezetet újra kell olvasnom, mert fontos lehet. A következő fejezet elején rájöttem, hogy itt az ideje újraolvasni az előző fejezetet.

-----

(&%;_98\<|{3W10Tut,P0/on&Jkj"Fg}|B/!~}|{z(8qv55sr1C/n--k**;gfe$$5a!BB]\.-

Na, az egy jó pillanatod volt. :-)
Kicsit komolyabban: keress rá a malbolge kifejezésre. Az igazsághoz tartozik, hogy amikor találkoztam a Malbolge nyelvvel, akkor elég sok dolgot elolvastam róla, de azóta szinte majdnem mindent elfelejtettem már. Ha elég sokat olvasol, akkor rájössz, hogy miért lehet gyorsan felejteni. :-)

Egyébként ez az aláírásom :-) . Azt jelenti, hogy „ironcat” (idézőjel nélkül). Malbolge nyelven van. Egy-két éve a HUP-on olvastam erről a nyelvről.
Info: https://en.wikipedia.org/wiki/Malbolge_programming_language

Az oldalán alján van link egy portugál nyelvű blogra. Ott meg kell keresni a linket a malbolge-sdk.tgz-re, és azzal lehet „Hello World" stílusú programokat készíteni.

Kiegészítés: a gyakorlati haszna nagyon gyorsan tart a nullához. :-)

-----

(&%;_98\<|{3W10Tut,P0/on&Jkj"Fg}|B/!~}|{z(8qv55sr1C/n--k**;gfe$$5a!BB]\.-

a reddit eleg jol porog haskell temakorben, http://www.reddit.com/r/haskell/. Erdemes olvasni. Az Simon Peyton Jones videok szenzaciosan jok - kivetel nelkul mindegyik https://www.haskell.org/haskellwiki/Video_presentations. Ez pedig egy jo kedvcsinalo : https://www.youtube.com/watch?v=b9FagOVqxmI

itt pedig arrol van szo hogy "haskell is useless" https://www.youtube.com/watch?v=iSmkqocn0oQ (SPJ) :)

Nekem valamiért ez a megoldás ugrott be először:

sum [0, 3..999] + sum [0, 5..999] - sum [0,15..999] 

Csak hogy meglegyen.

Scala:


(for(x <- 0 to 999 if x % 3 == 0 || x % 5 == 0) yield x).sum

Erlang:


lists:sum([X || X <- lists:seq(0, 999), (X rem 3 == 0) or (X rem 5 == 0)]).

Nem lenne kedve valakinek kicsit élvezkedni és sebesség mérést csinálni a felsorolt megoldásokból? :D

Nekem a Ruby 65%-al gyorsabban futott mint Python 2 és 3, kíváncsi lennék a többi interpretált nyelv milyen sebességet hoz :)

http://pastebin.com/HNeHrsYA

time g++ -ggdb -ftemplate-depth=10000 test.cpp -otest
real 0m0.770s
user 0m0.687s
sys 0m0.083s

time g++ -ggdb -ftemplate-depth=10000 test2.cpp -otest2
real 0m0.212s
user 0m0.177s
sys 0m0.036s

time ./test
(...)
real 0m0.039s
user 0m0.005s
sys 0m0.017s

time ./test2
(...)
real 0m0.562s
user 0m0.509s
sys 0m0.019s

clang-gal le se fordul a test1.cpp :(

(gcc g++-a meg nincs epp fent mert aranylag uj a Mac, es nagyon regen C/C++-oztam)


$ clang++ test.cpp -o test
test.cpp:2:77: fatal error: recursive template instantiation exceeded maximum depth of 256
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9744>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9745>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9746>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9747>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9748>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: (skipping 247 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see
      all)
test.cpp:2:77: note: in instantiation of template class 'Sum<9996>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9997>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9998>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9999>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:6:27: note: in instantiation of template class 'Sum<10000>' requested here
    unsigned long int x = Sum<10000>::value;
                          ^
test.cpp:2:77: note: use -ftemplate-depth=N to increase recursive template instantiation depth
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
1 error generated.

Tudom :)

De ez igazabol csalas, azert gyorsabb a "funkcionalis" megoldas, mert csomomindent elore kiszamol a fordito. :) Olyan mintha define-olnad az osszes 10000 sort elore, nem pedig real time szamoltatnad :)

Meg egy ilyen eredmenyt amugy is elcache-elsz vagy elore kiszamolsz mindenhol :)

(Es most lusta vagyok utananezni a clang ftemplate-depth megfelelojenek, gepem ki is van mar kapcsolva)

Tényleg késő lehetett: a hibaüzenetben ui. ott van a megfelelő kapcsoló :-)

Egyébként írtam is, hogy ez nagyobb fordítási időt eredményez.

Amit érdemes lehet tudni: a C++ template-kkel lehet (de érdemes?) funkcionálisan programozni, maga a programkód (pl. template példányosítás) lesz az input. Egyébként monadokat is csinálhatsz...

Olvastam olyan véleményt, hogy a C++ template megértéséhez hasznos a FP ismerete.

clang++ elsegfaultol:


$ time clang++ -ftemplate-depth=100000 test.cpp
clang: error: unable to execute command: Segmentation fault: 11
clang: error: clang frontend command failed due to signal (use -v to see invocation)
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
clang: note: diagnostic msg: PLEASE submit a bug report to http://developer.apple.com/bugreporter/ and include the crash backtrace, preprocessed source, and associated run script.
clang: note: diagnostic msg: 
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /var/folders/jz/nltfyqt91t90fqh5sjmnfp700000gn/T/test-2fb360.cpp
clang: note: diagnostic msg: /var/folders/jz/nltfyqt91t90fqh5sjmnfp700000gn/T/test-2fb360.sh
clang: note: diagnostic msg: 

********************

real	0m1.263s
user	0m0.277s
sys	0m0.044s

$ clang --version
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix

OS X 10.10 develpoer tools-hoz gyarilag jaro clang verziorol van szo

Update: a hatar 1406 es 1407 template kozott van:


$ time clang++ -ftemplate-depth=1406 test.cpp -o test
test.cpp:2:77: fatal error: recursive template instantiation exceeded maximum depth of 1406
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<8594>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<8595>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<8596>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<8597>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<8598>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: (skipping 1397 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see
      all)
test.cpp:2:77: note: in instantiation of template class 'Sum<9996>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9997>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9998>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:2:77: note: in instantiation of template class 'Sum<9999>' requested here
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
test.cpp:6:27: note: in instantiation of template class 'Sum<10000>' requested here
    unsigned long int x = Sum<10000>::value;
                          ^
test.cpp:2:77: note: use -ftemplate-depth=N to increase recursive template instantiation depth
template <unsigned long N> struct Sum { enum { value = ((N%3)&&(N%5)?0:N) + Sum<N - 1>::value };};
                                                                            ^
1 error generated.

real	0m0.264s
user	0m0.229s
sys	0m0.031s

$ time clang++ -ftemplate-depth=1407 test.cpp -o test
clang: error: unable to execute command: Segmentation fault: 11
clang: error: clang frontend command failed due to signal (use -v to see invocation)
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
clang: note: diagnostic msg: PLEASE submit a bug report to http://developer.apple.com/bugreporter/ and include the crash backtrace, preprocessed source, and associated run script.
clang: note: diagnostic msg: 
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /var/folders/jz/nltfyqt91t90fqh5sjmnfp700000gn/T/test-ed1686.cpp
clang: note: diagnostic msg: /var/folders/jz/nltfyqt91t90fqh5sjmnfp700000gn/T/test-ed1686.sh
clang: note: diagnostic msg: 

********************

real	0m0.503s
user	0m0.263s
sys	0m0.042s

Barmelyik, ami forditasi idoben megmondja az eredmenyt, nyerni fog.

Egy joliranyzott Hy makroval peldaul gyorsabb lesz a megoldas, mint az alap Python. (Es tippre igy Rubyt is verne)

Persze a meresnel illik ugy merni, hogy egyreszt nem egy futast merunk, masreszt az interpreter startup timejat nem merjuk bele.

--
|8]

Interpretált nyelvekre értettem. Másrészt én is úgy gondoltam, hogy a runtime betöltést nem mérjük. :) Illetve legyen 0 és 1 millió között.

Ha valaki nem akar utánanézni és nem használ Ruby-t, a Ruby példát megadhatom:

ruby -e 'require "benchmark"; p Benchmark.realtime { (0..999999).select{|x| x % 3 == 0 or x % 5 == 0}.inject(:+) }'


(defmacro euler-1-macro []
  (sum (list-comp x [x (range 0 1000)]
                  (or (= (% x 5) 0)
                      (= (% x 3 ) 0)))))

Ez kb ennek a python kodnak felel meg:


233168L

Igy a benchmarkolasa:


python -m timeit "233168L"

Ez nagyjabol 10000x gyorsabb, mintha futasi idoben futna a szamolas. Annyi a kulonbseg, hogy itt "forditasi" (ertsd: AST generalasi) idoben fut le a lenyeg. Nyilvan eroltetett pelda, de mokasnak mokas, es jol mutatja miket lehet csinalni egy joliranyzott makroval ;)

--
|8]