Funkcionalno programiranje (Haskell)

poruka: 37
|
čitano: 9.989
|
moderatori: Lazarus Long, XXX-Man, vincimus
+/- sve poruke
ravni prikaz
starije poruke gore
15 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Sad sam pregledao, i nemalo sam zacudjen - niti jedna tema o funkcionalnom programiranju, a kamoli o Haskellu!

 

Ne znam da li je to zato jer ljudi ne znaju, ili se nisu sjetili organizirati temu, ili sto vec no - ima li ovdje ikoga tko je barem zainteresiran za FP i prckao je tu i tamo s time, nebitno koji tocno jezik, da dijelimo iskustva, tehnike, etc?

 

Moja main teorija je da ce FP kroz najduze 8 godina kompletno istisnuti propisni OOP pardigmu i ovog modernog mutanta kojeg se iz navike zove OOP a s OOP-om nema nikakve veze, i barem po svojem iskustvu - mislim da svaki programer moze jako puno nauciti prisilivsi se prilagodbi na FP tehnike. Mnoge se daju aplicirati u bilo kojem imperativnom jeziku bez znacajnih gubitaka u performansama, a medju njima ima i takvih koje te iste performanse mogu i poboljsati.

Osobno sam potpuno napustio OOP (u bilo kojem jeziku) i od tri posla koja sam promjenio u medjuvremenu, vrlo strogo drzim stav da za veliku vecinu problema - tipicne OOP tehnike samo prodaju iluziju jednostavnosti i da se kod koji se treba kroz godine dopunjavat i odrzavati moze samo izgubiti programirajuci na taj nacin.

 

FP se -kratko receno- bazira na konstantama (variable ne postoje, barem ne onakve na kakve je imperativni programer navikao), a code reuse se bazira na strogo definiranim tipovima i kompoziciji, no ovaj put - funkcija, funktora, aplikatora, monada, strelica, etc.

 

Trenutno vrtim par hobi projektica u Haskellu ovako za zabavu (roguelikes :-D), rado cu podijeliti iskustva :-)

 

Pisite, pitajte...

I lived to see the end of my dreams, and then I nearly died so should I make up new dreams?
 
6 0 hvala 3
15 godina
odjavljen
offline
Re: Funkcionalno programiranje (Haskell)

Eto, prvo pitanje.

 

Why? Zašto prelaziti na funkcionalno programiranje? Koji su benefiti? Neki konkretan (kratki primjer)?

 

Ok, to nije jedno pitanje

Ovaj forumaš je netolerantan prema osobama svih nacionalnosti, rasa i spolnog opredjeljenja te smatra da svaka osoba ima pravo biti ugnjetavana zbog svojih glupih mišljenja.
15 godina
neaktivan
offline
Re: Funkcionalno programiranje (Haskell)
Sum_of_all_fears kaže...

Eto, prvo pitanje.

 

Why? Zašto prelaziti na funkcionalno programiranje? Koji su benefiti? Neki konkretan (kratki primjer)?

 

Ok, to nije jedno pitanje

Pa, iskreno, ima tu ponesto religije ali uglavnom odgovor se svodi na: produktivnost (razlozit cu kasnije) i jeftin multithreading.

 

Produktivnost:

1. zato jer uglavnom ne sreces probleme kakve sreces u imperativnim jezicima; nedostatak globalnog stanja jednostavno smanjuje kompliciranost na kontekst jedne jedine funkcije - output doslovce ovisi samo o inputu i tocka

2. zato jer je kompozitivnost funkcija i 'higher level funkcija' (aplikatori, funktori, monadi...) visestruko fleksibilniji koncept od kompozicije objekata, da li kroz asocijaciju ili nasljedjivanje, tako da je i code reuse puno 'jaci'

3. zato jer nacin razmisljanja, ako ti sjedne u glavu, moze puno bolje opisati problem bez 'prljanja' koda dodatnom funkcionalnosti koja moze a i ne mora smetati

 

Prakticki gledano, umjesto kodiranja s pitanjem "kako" u glavi, odgovaras na pitanje "sto". Umjesto mutiranja stanja, opisujes funkcionalnost. Umjesto objekata, komponiras funkcije. Ako imas potrebu pratiti stanje - to se izrazava eksplicitno (primjerice, generacija random brojeva vraca random broj i novi generator, koji koristis za slijedeci broj).

 

Nije nuzno kompletno preci na funkcionalno programiranje (iako ja mislim da je to najbolja usluga koju si iskusan programer moze napraviti), vec jednostavno se nauciti koncepte. Ciste funkcije i monadi su primjenjivi u maltene bilo kojem jeziku, a na vrlo elegantan nacin rijesavaju mnostvo problema kao sto je primjerice NPE (iako se to dalo rijesiti i s Null Object patternom, ali dobro sad).

Mislim da je dobar potez prisiliti se instalirati npr. Haskell (jer jedini forsira cistocu do kraja i strogo separira IO code od cistog codea), i onda kad se uvidi koliko je u biti tesko nauciti se drugacije razmisljati - postati zainteresiran za to.

 

Kazu da kad covjek jednom 'skuzi' Haskell, svi ostali jezici mu postanu naporni i dosadni, i ja se s time kompletno slazem. Konstrukcije tipova, polu-primjenjene funkcije, kompozicije i sve ostalo sto se u haskellu uzima zdravo za gotovo su tako mocni koncepti da imam dojam kao da iz vlaka sidjem na romobil svaki put kad se moram vratiti na neki drugi jezik.

 

Sample?
Pa, savjetujem ti stock example: proguglaj kako napisati quicksort u Haskellu. Ako me sjecanje ne vara, mislim da je svega 7 linija.

I lived to see the end of my dreams, and then I nearly died so should I make up new dreams?
15 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Nema bas radoznalih, ha?

Nema veze... odrzavat cu temu zivom kako-tako dok se ne pojavi netko hrabar i dovoljno zainteresiran.

 

Kratak tutorial sa jako dobrim primjerom rijesavanja problema koristeci 'naprednije' tehnike kao sto su monadi, u ovom slucaju je to State:

 

http://www.lpenz.org/articles/hedsl-sharedexpenses/

 

 

Vjerojatno ce preletjeti preko glave svakom tko ne zna Haskell, ali slobodno pitajte, probat cu objasnit sto znam.

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
 
2 0 hvala 2
12 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Pa mogao bi početi s nečim tipa "Hello World" gdje se može vidjeti struktura tipičnog haskell programa, tijek i način izvođenja i sl. Pričati o naprednijim konceptima je teško kada se niti ovakve stvari ne znaju.

Moj PC  
7 0 hvala 0
15 godina
offline
Funkcionalno programiranje (Haskell)

Bok,

evo jedno pitanje koje je možda malo van teme. Donekle si svladao (ne mislim vrijeđati, samo znam da uvijek ima mjesta za napredak) FP i Haskell te vidiš u tom principu budućnost programiranja. Da li iz ove perspektive možeš dati svajet nekom tko manje pozna programiranje da možda krene drugim putem ako cilja na FP tj. da si od početka znao da želiš ovako programirati kako bi krenuo prema svladavanju toga.

 
1 0 hvala 0
15 godina
neaktivan
offline
Re: Funkcionalno programiranje (Haskell)
franina kaže...

Bok,

evo jedno pitanje koje je možda malo van teme. Donekle si svladao (ne mislim vrijeđati, samo znam da uvijek ima mjesta za napredak) FP i Haskell te vidiš u tom principu budućnost programiranja. Da li iz ove perspektive možeš dati svajet nekom tko manje pozna programiranje da možda krene drugim putem ako cilja na FP tj. da si od početka znao da želiš ovako programirati kako bi krenuo prema svladavanju toga.

Nisam bas shvatio pitanje. Ako netko zeli uciti FP, definitivno mu savjetujem da ide uciti direktno FP i ostavi se drugih paradigmi jer se vrlo malo znanja nalazi u oba slucaja (API-ji su iskljuceni iz ove poredbe), a nacin razmisljanja nikako.

Haskell preporucam jer je vrlo striktan sto se tice separacije cistog i 'necistog' codea i vrlo je ekspresivan po pitanju tipova, tako da ce forsirati dobre navike kroz compiler. Neke stvari koje prolaze u Scali, Erlangu i Clojureu npr. u Haskellu ne mogu proci, nekad cak i s eksplicitnim ekstenzijama.

 

 

TracerCPP kaže...

Pa mogao bi početi s nečim tipa "Hello World" gdje se može vidjeti struktura tipičnog haskell programa, tijek i način izvođenja i sl. Pričati o naprednijim konceptima je teško kada se niti ovakve stvari ne znaju.

Kuzim sto zelis reci, no mislim da takvih tutoriala ima koliko hoces tako da ih nema smisla ponavljati osim u slucaju da netko ovo zeli nauciti a ne razumije engleski, no u tom slucaju mislim da je problem negdje drugdje.Jednostavno je izguglati osnove (eg. tvoj primjer - main = putStrLn "Hello world") no ja sam se osobno dosta pogubio maltene cim napustis te osnove, a pocnes se pitati kako rijesiti neki 'prakticni' problem (eg. kako napraviti imenik?)

 

Primjerice, ako netko zaista pocne s tutorijalima pa se javi i napise "Ne razumijem tocno kakvu svrhu imaju funktori" onda se tu moze razviti lijepa diskusija iz koje svatko, ukljucujuci naravno i mene, moze nauciti, i to ne samo za FP vec i za ostale jezike; mnogi imaju koncept funktora ostvaren da li direktno kroz sintaksu ili posredno kroz kakav API.

 

S druge strane, pisati monolog-tutorijal na hrvatskom od pocetka mi se cini redundantno.

Radije bih vodio dijalog.

 

 

Doduse, kad razmislim:

moze se otvoriti puno pitanja i s bazicnim hello world primjerom ako se razjasni prva nedoumica - 'main' u Haskellu nije funkcija vec vrijednost tipa "IO ()", sto znaci IO type parameteriziran s praznim tupleom, a putStr je funkcija koja prima tip String i vraca "IO ()" vrijednost. Zasto? Zato jer putStrLn ima 'side effect' (isprintat ce neku vrijednost na konzolu) ali ne vraca nista upotrebljivo, stoga prazan tuple.

 

U Haskellu svaki izraz koji na neki nacin pristupa vanjskom svijetu (IO - file system, konzola, display, audio, etc) 'zivi' u IO vrijednosti, sto prakticno znaci da ukoliko izraz nije na neki nacin agregiran u main vrijednost - nece se nikad izvrsiti. IO vrijednosti se prakticno "sumiraju" u kompozitnu kalkulaciju kroz bind funkciju i ta vrijednost u gotovo svakom programu postaje 'main'.

Bind funkcija je glavna funkcija za svaku monadsku vrijednost, i IO je kao takav, naravno - monad.

 

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
Poruka je uređivana zadnji put pon 16.5.2016 22:26 (Deus ex machina).
15 godina
offline
Re: Funkcionalno programiranje (Haskell)

Ima tutoriala, ima svega.

Al daj ti nama usporedi neki jednostavan programcic u javi, pythonu, c/c++ s istovjetnim kodom u haskellu tak ce se najlakse vidjet razlika, par prednosti i mozda koja mana.

Linux, Arch Linux. Dvorak keyboard layout. MTCNA
15 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Sasvim nelosa ideja, prepravio bih samo jedan dijelic - nek netko napise neki programic u Javi, Pythonu, C-u ili C++ u, ja cu ga pokusati prepraviti u Haskell :-)

 

Samo par primjera:

Java

class Whatevs {
   public static void main(String[] args) {
     System.out.printLn("Hello world");
   }
}

 

Haskell

main = putStrLn "Hello world"

 

 

Zbrajanje s brojem u listu brojeva:

Java

class Whatevs {
   public static void main(String[] args) {
     List<Integer> l = Arrays.asList(new int[] {0,1,2,3,4,5,6,7,8,9});
     List<Integer> o = new ArrayList(l.size());
     for (int v : l)
       o.add(v + 2);

   }
}

 

Haskell 

main = (_ -> map (+2) [0..9]) >> return ()

 

 

Ucitavanje text filea i printanje svake rijeci u novi red:

Java

class Whatevs {
   public static void main(String[] args) {
     try (FileReader fr = new FileReader(new File("textfile"))) {
       String line;
       while((line = fr.readLine()) != null) {
         for (String w : line.split(" ")) {
           System.out.println(w);
         }
       }
     }
   }
}

 

Haskell

main = readFile >=> foldl1 (>>) . map putStrLn . concat . map words . lines $ "textfile"

 

 

Eto.

Pitanja, slobodno.

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
Poruka je uređivana zadnji put uto 17.5.2016 18:38 (Deus ex machina).
 
6 0 hvala 2
15 godina
odjavljen
offline
Re: Funkcionalno programiranje (Haskell)

Mogli bi reći da je LINQ (u .Netu) jako, jako blizu tome.

 

Ne znam koliko si gledao po tome (linq, lambde, delegati, virtualne metode...) ali dobar dio ovih ružnih for...next gluposti se rješava sa njime. Primjer:

 

List<Person> persons = new List<Person>();

persons.Add(new Person(1, "Pero", "Perić");

....

persons.Add(new Person(7, "Marko", "Marković");

persons.Add(new Person(8, "Ivo", "Ivić");

 

var someUsers = persons.Where(x => x.Id > 6);

Ovaj forumaš je netolerantan prema osobama svih nacionalnosti, rasa i spolnog opredjeljenja te smatra da svaka osoba ima pravo biti ugnjetavana zbog svojih glupih mišljenja.
16 godina
neaktivan
offline
Re: Funkcionalno programiranje (Haskell)
Sum_of_all_fears kaže...

Mogli bi reći da je LINQ (u .Netu) jako, jako blizu tome.

 

Ne znam koliko si gledao po tome (linq, lambde, delegati, virtualne metode...) ali dobar dio ovih ružnih for...next gluposti se rješava sa njime. Primjer:

 

List<Person> persons = new List<Person>();

persons.Add(new Person(1, "Pero", "Perić");

....

persons.Add(new Person(7, "Marko", "Marković");

persons.Add(new Person(8, "Ivo", "Ivić");

 

var someUsers = persons.Where(x => x.Id > 6);

 Ovdje bar znamo o čemu se radi, persons mora podržavati IEnumerable<T> interface, odnosno biti kolekcija podataka. where je extension method koji na svakom elementu kolekcije izvodi anonimni metod koji compiler napravi od lamda izraza.

Ako anonimni metod za pojedini element kolekcije vrati true extension method where u novu kolekciju vrati taj element. Ispod haube i dalje iteriramo kolekciju, u biti, ovaj kod izvršavamo tek iteracijom nove kolekcije.

Kako bi se ova linq linija napravila kod njega i u čemu je razlika i u kodu i ispod haube, je li slično našim lambdama i mene interesira.

Poruka je uređivana zadnji put sri 18.5.2016 13:32 (Floki).
15 godina
neaktivan
offline
Re: Funkcionalno programiranje (Haskell)
Sum_of_all_fears kaže...

Mogli bi reći da je LINQ (u .Netu) jako, jako blizu tome.

 

Ne znam koliko si gledao po tome (linq, lambde, delegati, virtualne metode...) ali dobar dio ovih ružnih for...next gluposti se rješava sa njime. Primjer:

 

List<Person> persons = new List<Person>();

persons.Add(new Person(1, "Pero", "Perić");

....

persons.Add(new Person(7, "Marko", "Marković");

persons.Add(new Person(8, "Ivo", "Ivić");

 

var someUsers = persons.Where(x => x.Id > 6);

Floki kaže...

 Ovdje bar znamo o čemu se radi, persons mora podržavati IEnumerable<T> interface, odnosno biti kolekcija podataka. where je extension method koji na svakom elementu kolekcije izvodi anonimni metod koji compiler napravi od lamda izraza.

Ako anonimni metod za pojedini element kolekcije vrati true extension method where u novu kolekciju vrati taj element. Ispod haube i dalje iteriramo kolekciju, u biti, ovaj kod izvršavamo tek iteracijom nove kolekcije.

Kako bi se ova linq linija napravila kod njega i u čemu je razlika i u kodu i ispod haube, je li slično našim lambdama i mene interesira.

 

LINQ je uglavnom upravo FP orijentiran: umjesto loopova, koristis map i reduce (odnosno fold). Razlika je samo u tome sto je LINQ embeddan unutar OOP jezika, pa je samim time ogranicen sintaksom. Primjerice, koliko ja znam - u LINQ-u ne mozes parcijalno primjeniti funkcije/metode, ne mozes ih komponirati, i ne mozes forsirati cisti code (bez sideeffecta) kroz compiler, svo izvrsavanje je striktno (a ne lijeno), ne postoje beskonancne vrijednosti, etc... Vjerujem da postoji neki tip "Optional" ili "Maybe" koji pokusava imitirati monadske sposobnosti ali ako je to ista slicno javi - onda je poprilicno neugledno i ne-elegantno.

 

Sto se tice tipova - znas o cemu se radi i u Haskellu. Tipovi su staticki i striktni; razlika je u tome da ih ne moras (iako mozes) rucno pisati. Zbog nacina na koji tipovi funkcioniraju (algebarski,  teorija kategorija), compiler moze sam skuziti sto je koji tip.

Ideja da se tipovi trebaju 'komentirati' kroz code je nasljedje OOP-a, i nije problem u jeziku vec u nacinu razmisljanja - prvoj i najvecoj kocnici kod prelaska na neki FP jezik.

 

Postoji parameterizacija tipova (npr. kao templateovi u C++u ili generici u C#-u), i typeclass da bi se parameterizirani tip ogranicio. Vise-manje te stvari samo kreiraju los code (npr. existential typeclass antipattern), jer ljudi zaboravljaju da su funkcije uglavnom puno mocniji alat.

 

Nadalje, tipovi se ponasaju i kao tipovi, enumeracije i unioni. Primjerice, recimo da imamo tip Foo, mozemo napraviti dva konstruktora, Bar i Moo, koji uzimaju drugacije vrijednosti pored parameteriziranog tipa 'a':

data Foo a = Bar Int a | Moo String a

 

I na kraju, ono sto je po meni najbitnije - instancirati tip kao neku typeclassu ("naslijediti") moze se dogoditi svagdje, cime se postuje open-closed princip. Recimo da zelimo da nas tip bude Monad. Ovaj code moze stajati gdje god:

instance Monad Foo where
  return = Moo
  (Bar a) >>= f = f a
  (Moo a) >>= f = f a

 

 

Edit:

mislim da je zadnji primjer koji sam naveo u biti najinteresantniji, ne zato jer je one-liner, vec zato jer koristi sve sto Haskell stavlja barem klasu-dvije (;-)) ispred drugih jezika: monadi, kompozicija funkcija, kliesli strelice te parcijalna aplikacija.

main = readFile >=> foldl1 (>>) . map putStrLn . concat . map words . lines $ "textfile"

 

Pojasnit cu sto se dogadja:
$ operator je aplikator s najnizim mogucim prioritetom. Primjerice, bas kao sto su zbrajanje i mnozenje operacije drugacijeg prioriteta, tako i ovaj aplikator forsira aplikaciju funkcije tek nakon sto se sve ostalo razvije.
. je kompozicija funkcije, odnosno, output jedne funkcije postaje input druge, stvarajuci novu funkciju.
>=> je kliesli kompozicija koja omogucuje kompoziciju monada na slican nacin na koji se komponiraju funkcije.

>> operator je monadsko spajanje u kojem se vrijednost prethodnog monada zanemaruje.

 

Dakle, kod se cita od operatora najveceg prioriteta prema operatoru najnizeg. Operator aplikacije funkcije je najjaci (obican space, " "), dakle prvo rijesavamo funkcije map, koje uzimaju dva parametra: funkciju s jednim parametrom i listu. Kao sto vidimo, mi predajemo samo jedan parametar, sto se zove parcijalna aplikacija, i kao rezultat dobit cemo dvije funkcije koje imaju definiran prvi parametar ali im nedostaje drugi.

Nakon toga, rijesavamo . operator, komponirajuci funkcije s desna na lijevo:

lines ima tip String -> [String], odnosno iz stringa vraca listu stringova. Lines tokenizira string po newlinesima.

To se komponira na parcijalno aplicirani "mapWords" koji prima listu stringova i vraca listu listi Stringova [[String]]. Words tokenizira string po spaceovima.

Onda ide concat, koji prima listu listi bilo cega, i konkatenira liste u jednu veliku, dakle [[a]] -> [a]

Onda opet parcijalno aplicirani map koji uzima listu Stringova i kreira listu IO () vrijednosti, dakle [IO ()]. Ove IO vrijednosti imaju sideeffect da isprintaju dani string na konzolu.

Nakon toga ide fold [IO ()] u singularni IO (), i to se radi kroz operator >>, odnosno, lancano spajamo IO () vrijednosti jednu za drugom u jednu veliku akciju. Operator >> ima tip u ovom slucaju IO a -> IO b -> IO b, sto znaci uzima IO s tipom a i IO s tipom b i vraca IO s tipom b (gdje naravno a i b mogu biti isti tipovi).

Koristim fold funkciju 'fold1' sto znaci da foldam listu s lijeva nadesno i bez startne akumulacijske vrijednosti; prva vrijednost je ujedno i prva vrijednost iz liste.

 

Tip ove velike anonimne funkcije je sada: String -> IO ()

S obzirom da je ulazna vrijednost 'cista' a izlazna monadska, mozemo upotrijebiti monadsku kompoziciju (>=>) i lancano spojiti readFile izlaz na ulaz nase funkcije. readFile vraca "IO String" vrijednost, odnosno String zamotan u IO monad (jer se taj string dobija kroz sideeffect). Kad to spojimo kroz monadski bind, nasa anonimna funkcija prima String ali mora obavezno vratiti vrijednost zamotanu u isti monad (IO) sto se vec dogadja.

readFile ima tip String -> IO String, sto znaci da to komponirano s nasom funkcijom sad ima tip String -> IO ()

 

main trazi IO () tip, sto znaci da trebamo aplicirati String vrijednost na nasu monadsku funkciju i tu u pricu ulazi aplikator $ jer se to "izvrsava" zadnje. Dakle, aplicirajuci String "textfile" na String -> IO (), dobijamo IO () vrijednost koju mozemo pridruziti u main.

 

Voila.

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
Poruka je uređivana zadnji put sri 18.5.2016 15:39 (Deus ex machina).
12 godina
offline
Re: Funkcionalno programiranje (Haskell)
Deus ex machina kaže...
Ucitavanje text filea i printanje svake rijeci u novi red:

Java

class Whatevs {
   public static void main(String[] args) {
     try (FileReader fr = new FileReader(new File("textfile"))) {
       String line;
       while((line = fr.readLine()) != null) {
         for (String w : line.split(" ")) {
           System.out.println(w);
         }
       }
     }
   }
}

 

Haskell

main = readFile >=> foldl1 (>>) . map putStrLn . concat . map words . lines $ "textfile"

 

 

Eto.

Pitanja, slobodno.

 

Evo samo za Javu, ako ćemo baš stegnut remen :). Platforma JVM.

Ucitavanje text filea i printanje svake rijeci u novi red:

public class Main {
    public static void main(String args[]) throws IOException {
        Files.lines(Paths.get("c://lines.txt")).forEach(System.out::println);
    }
}

 

Evo i primjer za Scalu

Scala (http://www.scala-lang.org/Object-Oriented Meets Functional) kao nešto što je nastalo na "problemima" Jave (wiki). Platforma JVM.

Ucitavanje text filea i printanje svake rijeci u novi red:

import scala.io.Source
for(line <- Source.fromPath("c://lines.txt").getLines()) println(line)

 

Pozdrav (pratim i dalje temu)

15 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Zgodno i iznenadjujuce, nedavno sam gledao novitete u Javi i vidio da guraju malo funkcionalnih stvari, ali kad sam vidio Optional, smucilo mi se. Pomislio sam da je sve tako nezgrapno rijeseno. Ovo izgleda puno bolje.

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
 
0 0 hvala 0
16 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Ima tu i Microsoft konja za trku, F#

 

Sama lambda ide ovako

 

 let result = (fun x y -> x + y) 5 4
 printfn "%d" result

 

Da bi dobili fleksibilnost i pozivali različite funkcije uvodimo function value, pa možemol pozvati funkciju koju hoćemo uz uvjet da funkcija odgovara.

 

 let a (f: int -> int -> int) x y = f x y
 let result = a (fun x y -> x * y) 5 4
 printfn "%d" result

Poruka je uređivana zadnji put sri 18.5.2016 21:00 (Floki).
 
0 0 hvala 0
15 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Velika prednost Haskella je u tome sto se drzi striktno funkcijske paradigme, implementira software patterne kroz visu matematiku, te kroz striktne tipova separira -na razini compilera- cist code od IO codea. Ima drugih jezika koji se drze cisto jedne paradigme, (npr. Erlang i Clojure) ali nemaju striktnu separaciju, ocekuje se od korisnika da na to pazi. Dokle to moze pomoci u produkcijskoj okolini, smatram da pocetnicima samo otezava ispravno ucenje.

 

Sto se tice multi-paradigm jezika (cak i Python ulazi ovdje jer ima stvarno fino razvijene FP facilitye), vidim mnogo ljudi u beginners channelima na IRC-u kako -nazalost- prenose znanja i navike iz drugih paradigmi u funkcionalnu, i samim time sebi odmazu. Naravno, ljudi uce na drugacije nacine, no mislim da je jedini nacin da se vide sve prednosti i mane funkcionalnog programiranja - programirati funkcionalno. Ako odjednom nemas pristup varijablama, loopovima i ostalim imperativnim konstruktima, morat ces se prisiliti razmisljati na drugaciji nacin (ili odustati), a u tome lezi srz ucenja neceg novog.

Haskell je vrlo neugodan u pocetku, sve se cini napornim i neprirodnim; problem nije u jeziku, nego u navikama.

 

Ovaj topic u Quori je okupio pristase FP jezika, i nasiroko objasnjava ono sto sam ja u pocetku pokusao sazeti:

https://www.quora.com/What-are-the-pros-and-cons-of-F-versus-Haskell-as-functional-programming-languages

"For that reason I'd advise Haskell if you want to ensure you get the gist of functional programming fully. Else you'd need to check yourself every time to make sure you didn't simply write a translated imperative algorithm."

 

@Floki:

jel moguce u F#-u parcijalno aplicirati?

Primjerice, jel mozes pozvati (+) sa samo jednom vrijednosti, i dobiti natrag funkciju koja prima jedan parametar manje?

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
Poruka je uređivana zadnji put sri 18.5.2016 21:50 (Deus ex machina).
 
0 0 hvala 0
16 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Ne znam to napraviti, ako se i može, ali to nisam vidio.

 

Iskušavao sam nešto malo F#, čisto su mi se svidjele neke matematičke fore, ali nisam išao daleko.

Što se tiče tih recenzija što si ih naveo, nije sporno, a znaš kako MS radi, stavi u VS F# template, pa bode oči svaki put kad radiš novi projekt, jednom i probaš, prije nego i čuješ za druge.

 

Svidjela mi se kombinacija funkcija i te stvari, npr ovako, ali to nisam radio što pitaš, jedino znam ovakve kombinacije da funkcija square prima funkciju factorial i kvadrira je.

 

  let rec factorial n = if n <= 1 then 1 else n * factorial(n-1)
  let square(f: int -> int) n = f(n) * f(n)
  printfn "%d" (square factorial 3)

Poruka je uređivana zadnji put sri 18.5.2016 22:45 (Floki).
 
1 0 hvala 0
16 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Odlicna tema!

Sto se tice funkcijskog (ne funkcionalnog :P) programiranja nekada davno bio sam na par predavanja, onda u nedostatku vremena odustao. Kad si me vec sjetio na to, dobio sam ideju da ove godine dovrsim zapoceto.

 

Jedan od velikih pluseva FP je sto je puno, puno lakse formalno, matematicki dokazati ispravnost programa. Kod imperativnih jezika taj je problem puno tezi, postoje alati poput NuSMV-a koji koriste BDD i SAT rjesivace, a SAT je jedan od prvih problema za koji je dokazano da je NP tezak sto predstavlja poprilican problem.

 

A sto se koristenja tice, s obzirom da najvise programiram u Pythonu, redovito koristim list comprehension, generatore, lambda funkcije (iako osakacene u odnosu na punokrvni FP jezik), map (iako ga se da zamijeniti list comprehensionom) i reduce. Takoder, u Pythonu su funkcije gradani prve klase (kao i ostalo xD). No, to je to. Python nije nesto brutalan po pitanju FP-a, to je prvenstveno OO jezik s primjesama FP-a (nema izrazito bitne tail rekurzije, npr.). Tako da je Python izrazito krasan kad se pise OO, ali kad se pise neki ozbiljniji FP, onda je prilicno manje krasan :D. Medutim, za jednostavne stvari je ok. EDIT: Jos kad se sjetim da Guido svako malo prijeti da ce izbaciti map, reduce i filter, haha.

 

To je otprilike to sto se tice mog poznavanja FP-a. Pratim temu i dalje (za vise cu se javiti tamo negdje krajem ove godine xD).

Perhaps today IS a good day to die. PREPARE FOR RAMMING SPEED!
Poruka je uređivana zadnji put sri 18.5.2016 23:11 (1domagoj1).
 
3 0 hvala 0
8 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)
https://wiki.haskell.org/Frag
:)
znao sam da mi je bilo poznato odnekuda
 
1 0 hvala 1
15 godina
neaktivan
offline
Re: Funkcionalno programiranje (Haskell)
Floki kaže...

Ne znam to napraviti, ako se i može, ali to nisam vidio.

 

Iskušavao sam nešto malo F#, čisto su mi se svidjele neke matematičke fore, ali nisam išao daleko.

Što se tiče tih recenzija što si ih naveo, nije sporno, a znaš kako MS radi, stavi u VS F# template, pa bode oči svaki put kad radiš novi projekt, jednom i probaš, prije nego i čuješ za druge.

 

Svidjela mi se kombinacija funkcija i te stvari, npr ovako, ali to nisam radio što pitaš, jedino znam ovakve kombinacije da funkcija square prima funkciju factorial i kvadrira je.

 

  let rec factorial n = if n <= 1 then 1 else n * factorial(n-1)
  let square(f: int -> int) n = f(n) * f(n)
  printfn "%d" (square factorial 3)

Zgodan mi je ovaj F#!

No, za ovu potrebu, to mogu biti i funkcije i u OOP jeziku ili obicne lambde, ali svidja mi se sto se notacija koristi jednako svadgje, u haskellu izrazavas tipove na skoro isti nacin.

Pitam se da li ima pattern matching u F#-u (lijen sam proguglati), odnosno moze se izbjeci if <parametar> then / else u tijelu funkcije, i to gurnes u sam pocetak. Primjeti takodjer da u Haskellu zagrade koristimo iskljucivo za odredjivanje prioriteta operacije. Aplikacija funkcije je obican space izmedju imena i parametara i rijesava se s lijeva na desno (tehnicki, prvi parametar se aplicira i vraca funkciju s n-1 parametara, pa se aplicira drugi koji vraca funkciju s n-2 i tako do kraja).

 

Prepravit cu factorial u Haskell, ovaj put cu rucno napisati type cisto jer je dobra navika. I factorial i square imaju barem par nacina na koji se daju napisati

 

factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n - 1) -- naivno
-- factorial n = foldl (*) 1 [1..n]   -- foldanje limitirane liste s mnozenjem
-- factorial n = product [1..n]     -- produkt liste :-D

square :: (Int -> Int) -> Int
square f n = (f n) * (f n)     -- cista i jednostavna, naivna verzija
-- square f   = (*) <$> f <*> f   -- eta-redukcija (uklanjanje parametara) i higher level kompozicija funkcija
                  -- zbog cinjenice da su sve funkcije takodjer i funktori u Haskellu i vecini drugih FP jezika

 

Kao sto se vidi, pattern matching radi od prvog prema zadnjem, i mogu se koristiti konkretne vrijednosti za parametre (bas kao i u matematici za nekontinuirane funkcije ili za rubove). Tako funkcija kaze da je za factorial od 0 = 1, a za sve ostalo rekurzija. Pattern matching se moze normalno izvrsavati nad svakim tipom, i compiler pomaze kod nekompletnih patterna ili ambigous matchanja.

 

U drugoj definiciji squarea (ne mogu obje biti aktivne naravno!), aplicirao sam prvo f na operator mnozenja, a nakon toga toj funkciji pridruzio ponovno f.

To znaci da rezultat 'square' u drugoj varijanti vise nije vrijednost, vec funkcija Int -> Int!

 

Da stvar bude komicnija, ako bas zelis sprckati code do kraja i kriptirati ga, lol - moguce je ukinuti i f parametar, sprckati zajedno <$>, <*> i (*) operatore tako da u tijelu funkcije uopce ne moras specificirati niti jedan parametar :-D

Nisam siguran tocno kako, prva ideja mi je vratila gresku 'infinite type construction error':

square = (<*>) <*> ((<$>) (*))

, ali siguran sam da se moze :-D

 

Ovaj nacin rijesavanja problema je ono sto FP cini FP-om. U Bruce Eckelovoj knjizi o C++, on kaze da tko radi s C++-om a ne razumije/koristi virtualne funkcije - taj ne koristi OOP. Mislim da za FP i higher level funkcije ovo vrijedi jednako.

 

Sve u svemu, vrlo vrlo zgodno i mocno prckanje!

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
Poruka je uređivana zadnji put čet 19.5.2016 15:52 (Deus ex machina).
16 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Ima pattern matching u F#, dođe mu nešto slično kao switch statement.

 

let rec factorial n = match n with
        | 0 -> 1
        | _ -> n * factorial(n-1)
let square(f: int -> int) n = f(n) * f(n)
printfn "%d" (square factorial 3)

Poruka je uređivana zadnji put pet 20.5.2016 14:22 (Floki).
 
1 0 hvala 0
15 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Trenutno, gnjavim se dosta s monad transformerima. Razumijem princip, razumijem zasto i razumijem kako, no dok slazem code, sve mi se cini kao da vise pogadjam sto napraviti, nego zapravo razumijem sto radim.

Sredio sam EitherT Error IO () da radi (mogucnosti Either i IO) jer vrtim IO code koji moze propasti a ne zelim skrsiti aplikaciju... htio bi dodati logiranje s Writerom ali pogubio sam se.

 

Edit:

pet minuta kasnije, rascistio probleme. Sve radi ko puska. Tri transformera stackana jedan na drugi, jedino me buni intuicija. Covjek bi mislio da tip kaze, test vraca either koji je ili String, ili WriterT monad s IO-om (Writer je log), tako da logicki gledano ispada da ako dobijes lijevu stranu EitherT-a, onda ne dobijes ni log ni IO side-effecte.

No, kako je ispalo na kraju - transformere unwrappas s lijeva na desno, tako da prvi unwrap mora biti na EitherT-u (runEitherT) koji vraca WriterT String IO (Either String ()). Drugi unwrap vraca writer (koji ima tip (vrijednost, log)), tako da se dobije IO (Either String (), String).

 

pocetni type (Writer, Either i IO monadi)

test :: EitherT String (WriterT String IO) ()

 

izvrsavanje

runWriterT . runEitherT $ test

 

izlazni tip (koji se unutar IO monada -npr. main- moze bindati na neku funkciju koja prima tuple kojem je first Either, a second String), pa onda pozvati funkciju 'either' na first i vidjeti sto dalje. Log je prisutan u oba slucaja.

Cool!

IO (EIther String (), String)

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
Poruka je uređivana zadnji put pet 20.5.2016 18:57 (Deus ex machina).
 
0 0 hvala 0
16 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Pravo da ti kažem, već dulje vrijeme namjeravam pročitati ovu knjigu.

Poznato ti je da F# ima multi paradigmu, ovdje se obrađuje samo funkcijska paradigma uz pisanje algoritama.

http://shop.oreilly.com/product/9781783558476.do

 

Možda jednom postane mainstream, kako kažeš (ne ti sam doduše, nego neki autori knjiga isto to kažu).

Poruka je uređivana zadnji put pet 20.5.2016 21:47 (Floki).
 
0 0 hvala 0
15 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Znas kako kazu, da je posao programera konstantno ucenje?

Pa, ja sam gotovo siguran da je ovo to. Nauciti Python kad jednom znas npr. Ruby nije neki problem. U biti nauciti skoro bilo koji imperativni/OOP jezik kad vec znas jedan je nista.

Jedini jezik koji se razlikuje jest asembler, no on je toliko ovisan o hardveru da ne mozes skoro ni pricati o tome kako znas assembler generalno.

 

Ispravno funkcijsko (j*** se domagoj :-D) programiranje je tesko. Ne inherentno, nego zato jer je tesko okrenuti glavu u pravom smjeru i ostaviti stare navike, no prednosti koje donosi (neke sigurne, neke samo naslucujem) jednostavno ce pomesti svaki drugi jezik. Samo pricekaj da mladci sa faksa pocnu otvarati startupove na bazi funkcijskog programiranja. Mi starci, ako se ne prilagodimo - postat cemo obsolete.

 

Haskell je k'o Vim. Uzasna pocetna krivulja, ali jednom kad udjes u stos - vise neces ni pomisljati na ista drugo.

 

Jesi li probao neke bazicne programcice sastaviti u F#-u?

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
 
1 0 hvala 1
16 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Ako ću se pridržavati pravila FP, pa koristiti nepromjenjive tipove, tail rekurziju i onda bez petlji onda mogu ove naše temeljne algoritme napisati, za nešto složenijke pobjegao bi u mutable tipove i petlje, što u F# ne brane, ali onda to nije to.

 

 

Npr. ovo mogu, mada mi je čudno da ovakvu vrstu programa, odnsno tail rekurziju ne mogu pokrenuti u interaktivnom prozoru, a u konzolnoj aplikaciji ide bez probčlema.

 

let  factorization n =
    let rec factoring  n x =
        match (n=1) with
        | true -> printf " "
        | false ->
            match (n%x=0) with
            | true -> printf "%d " x ; factoring (n/x) x
            | false -> factoring n (x+1)   
    factoring n 2

Poruka je uređivana zadnji put pon 23.5.2016 16:12 (Floki).
 
0 0 hvala 0
15 godina
neaktivan
offline
Re: Funkcionalno programiranje (Haskell)

Iskreno, rekurziju sam koristio jednom ili dvaput, najvise. Rekurzija je kao 'goto' u imperativnom jeziku - ima primjenu, i primjenjeno na pravi nacin zaista cisti code, ali uglavnom nema smisla. Mapovi i foldovi su, ja mislim, osnovni principi - rade na listama (jer su liste funktori) i jednostavno je razviti intuiciju.

Kasnije, mozes 'upgradeati' map u 'fmap' - aplicirati funkciju na bilo koji funktor istog tipa, npr. Maybe (ne znam kako se Maybe zove u F#). U Haskellu, Maybe je i funktor, i applicative, i monad, i monoid, a mislim cak i Traversable. Kad 'doktoriras' Maybe, Either i te pocetne tipove, onda se okrenes natrag funkcijama, jer su i funkcije (barem u Haskellu) takodjer i funktori i applicative.

Tako da ti to nekako otvori vrata prema onome sto FP zapravo jest.

 

Probaj umjesto tih matematickih algoritama rijesiti neki drugi problem, cak i neko binarno stablo (append, delete, search) bi bila, ja mislim, puno bolja praksa.

 

Ja radim neki mali nethack (tj. dva).

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
Poruka je uređivana zadnji put uto 24.5.2016 14:49 (Deus ex machina).
16 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Dobra ideja sa binarnim stablom, hvala ti na tome

Da ispravim za ono gore, funkcija radi i u interaktivnom prozoru, zaboravio sam je registrirati u interaktivnom prozoru.

Poruka je uređivana zadnji put uto 24.5.2016 21:26 (Floki).
 
1 0 hvala 0
15 godina
neaktivan
offline
Re: Funkcionalno programiranje (Haskell)
Floki kaže...

Dobra ideja sa binarnim stablom, hvala ti na tome

Da ispravim za ono gore, funkcija radi i u interaktivnom prozoru, zaboravio sam je registrirati u interaktivnom prozoru.

 Cool beans, congrats :-D

 

Procitaj ovo, izguglao sam sada: https://en.wikibooks.org/wiki/F_Sharp_Programming/Computation_Expressions

 

Ne sjecam se tocno jesu li me monadi ili kompozicije gurnuli preko ruba, ali u svakom slucaju, vrlo vrijedno stivo. Nemoj da te obeshrabri uvodna recenica; monadi su u principu stvarno jednostavni ali zbunjuje njihova primjena upravo zato jer su drugaciji od svega na sto smo navikli u imperativnim programima.

 

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
15 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Jako fino slozeni odgovori.

Usporedjuje se type sistem Jave naspram Haskella.

 

http://programmers.stackexchange.com/questions/279316/what-exactly-makes-the-haskell-type-system-so-revered-vs-say-java

 

Java ima poprilicno bijedan, jednostavan i 'lazan' type sistem (govorim o genericima), C# je tu puno ekspresivniji. Dok je C++ kompletno premocan nad oboje, sve se to vrti oko jednakih principa s ponekim dodatkom.

 

Are you looking at me? Why do you keep looking at me? Am I not merciful? Am I not - merciful...
 
0 0 hvala 0
16 godina
neaktivan
offline
Funkcionalno programiranje (Haskell)

Aha, koncept tih monada je u stvari izvršavanje jedne funkcije i predaja njene povratne vrijednosti drugoj funkciji.

A maybe monad je onaj koji lanac funkcija privede kraju sa nekom vrijednošću ili prekine izvršavanje lanca i vrati none, ovisno o uvjetima.

 

Našao sam jedan zadatak na netu, od nekog x oduzimamo u nizu 10, 30 i 50, ako x kojeg smanjujemo oduzimajem tih vrijednosti bude manji  od tih djeljitelja program se prekida i vraća none, ako x bude veći od svih djeljitelja vraćamo taj krajnji x.

Primjer:

x = 100

100 - 10

90 - 30

60 - 50

x = 10

 

x = 5

5 - 10

x = None

 

Tip je napisao sugared verziju, a ja sam napisao desugared verziju i decrement verziju odnosno ručno napisani bind metod. Kad god sam zapeo, pomoglo je što sam vizualizirao u desugared verziji.

 

let tryDecr x n =
    match x > n with
    | true -> Some(x-n)
    | _ -> None

let decrement x  =
    let bind(input, rest) =
        match input with
        | Some a -> rest a
        | _ -> None
    bind(tryDecr x 10, fun y ->
        bind(tryDecr y 30, fun z ->
            bind(tryDecr z 50, fun t -> Some t)))

type MaybeBuilder() =
  member this.Bind(input, rest) =
         match input with
         | Some a -> rest a
         | _ -> None
  member this.Return(a) = Some a
 
let maybe = new MaybeBuilder()

let desugared x =
    maybe.Bind(tryDecr x 10, fun y ->
        maybe.Bind(tryDecr y 30, fun z ->
            maybe.Bind(tryDecr z 50, fun t ->
                maybe.Return(t)
            )
        )
    )

let sugared x =
    maybe {
        let! y = tryDecr x 10
        let! z = tryDecr y 30
        let! t = tryDecr z 50
        return t
    }

Poruka je uređivana zadnji put čet 26.5.2016 21:25 (Floki).
 
1 0 hvala 0
Nova poruka
E-mail:
Lozinka:
 
vrh stranice