[Tutorial] Haskell part 2

Pagina: 1
Acties:
  • 146 views sinds 30-01-2008
  • Reageer

  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

Topicstarter
(overleden)
Glimi's introductie tutorial Haskell, deel 2
:) Welkom bij deel 2 enzo :) Ik heb veel positieve reacties en nuttige kritiek mogen ontvangen n.a.v deel 1 :) Ik vond dat erg leuk om te zien. Maarja genoeg gewauwel, op naar deel 2 van de introductie van deze fantastische functionele taal ;)

Errata deel 1
Een van de kritieken die ik kreeg ging over het vergeten van het bespreken van het Char datatype. Dank u CyeZ ;). Ik heb hem bij deze toegevoegd.

Inhoud
Wat ga ik behandelen deze tutorial? Het gaat allemaal over functies! We zijn immers bezig met een functionele taal he ;) Ik zal met deze tutorial proberen zo veel mogelijk mogelijkheden van functies proberen te bespreken, zodat jullie weer aan de slag kunnen. Onderstaande lijst is klikbaar :)


  1. Declaratie van functies

  2. Naamgeving van functies

  3. Operatoren

  4. Conditionele code in functies

  5. Iteratie

  6. Functies op lijsten

  7. Vraagstukken en oefeningen



Declaratie van functies
In deel 1 hebben we het al gehad over hoe functies er nou eindelijk uit zien. We herhalen dit kort even.

Een functie bestaat uit een Signature en een Implementatie. De signature vertelt welke parameters de functie verwacht en van welk type zijn uitkomst zal zijn. De implementatie verzorgt dit dan. Voorbeeld:
code:
1
2
discriminant         :: Int -> Int -> Int -> Int   -- signature
discriminant a b c   = b*b - 4*a*c                 -- implementatie

Uit de discriminantfunctie signature lezen wij af dat hij 3 parameters verwacht (3 Ints). Vervolgens zal hij een Int opleveren. In de implementatie zien we vervolgens hoe hij dat doet, namelijk door b te kwadrateren en daar 4 x a x c van af te trekken.

Wen jezelf eraan altijd eerst een signature te schrijven en daarna pas de functie. Als dan namelijk errors krijgt dat je implementatie niet voldoet aan je sinature, dan weet je dat je functie niet werkt zoals jij dat gewild had. De foutmelding die je krijgt zal ongeveer zoiets zijn
code:
1
2
3
4
5
6
7
(4,32): Type error in infix application
 expression       : 4 * a
 operator         : *
   type           : Int -> Int -> Int
 right operand    : a
   type           : Char
   does not match : Int


Naamgeving van functies
Naamgeving van functies is erg belangrijk in programmeertalen. Functienamen horen altijd te beschrijven wat de functie doet en daarmee maakt het een functie zelf beschrijvend. Neem het volgende voorbeeld (en laten we het nut van de functies zelf vergeten :X):
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- Deze functie behoeft geen documentatie
isUnder250      :: Int -> Bool
isUnder250 num  = num < 250

-- Deze wel
functionA       :: Int -> Bool
functionA num   = num < 250

-- Hier zie je waarom
filterUnder250  :: [Int]
filterUnder250  = filter isUnder250 [1..1000]

-- Dit is niet te begrijpen zonder documentatie
filterUnder250' :: [Int]
filterUnder250' = filter functionA [1..1000]

filterUnder250 is duidelijk en behoeft eigenlijk geen commentaar, de naam omschrijft precies wat de functie doet. Dit is niet het geval bij filterUnder250'. Hierbij is het totaal onduidelijk wat er gefiltert gaat worden.

Behalve dat andere programmeurs eisen aan je functienamen stellen, eist Helium ook nog wat van functienamen. Misschien heb je ooit deze melding gezien:
code:
1
2
3
        Undefined constructor "Voorbeeld"
        Hint: Use identifiers starting with a lower case letter to define a function
        or a variable

De melding zegt het eigenlijk zelf al. Helium eist dat functienamen beginnen met een kleine letter. Functienamen met een hoofdletter zijn gereserveerd voor constructorfuncties. Op constructorfuncties kom ik terug bij het bespreken van datatypes.
De regels voor de naam van een functie zijn eigenlijk in 2 punten vast te leggen. Deze regels gelden ook voor parameters.
• Functies/parameters moeten beginnen met een kleine letter ( [a-z] )
• Daarna mogen een willekeurig aantal kleine letters/ hoofdletters/ cijfers / underscores / single quotes in elke volgorde volgen ( ( [ a-z] | [ A-Z ] | [0-9] | "_" | "'" )* )
Achter de regels staan de betreffende regular expressions. Als je die niet snapt, geen nood, dat doet niemand ;) :X

Voorbeelden van valide functie- en parameternamen (ja zelfs l337 style is mogelijk :P ):
code:
1
g h hg discriminant discriminant2 discriminant' discri'minant d15cr1m1n4n7 dis_cri_mi_nant


Deze namen zijn niet valide, zelfs al voldoen ze aan de eisen. Dat komt omdat ze gereserveerd zijn voor intern gebruik in Helium. Denk aan control structuren als if/else ed.
code:
1
2
3
case class  data    default deriving do     else
if   import in      infix   infixl   infixr instance
let  module newtype of      then     type   where

Onthoud overigens dat het conventie is om functies en parameters 'camelstyle' te schrijven. Dat wil zeggen, als een naam uit meerdere woorden bestaat, dan wordt elk woord (behalve de eerste) geschreven met een hoofdletter, aan het vorige woord vast. parseTree en prettyPrint voldoen aan deze conventie. Bedenk wel dat het een conventie is en geen eis van Helium.

Operatoren
In deze 'serie' :P zijn we al enkele keren operatoren tegengekomen. Neem bijvoorbeeld *, + en ==. Als je die operatoren goed gaat bekijken, zie je eigenlijk dat het eigenlijk gewoon functies zijn. Ze nemen gewoon parameters aan en retourneren een antwoord van de functie. Echter er zijn wel 2 verschillen tussen operatoren en gewone functies.
• Operatoren hebben altijd maximaal 2 operands
• Operatoren worden tussen de parameters geschreven in plaats van ervoor.

Echter in de essentie zijn operatoren en functies hetzelfde. Waarom zouden we dan geen operatoren kunnen definiëren? Natuurlijk kan dat wel!
code:
1
2
3
-- Compute the difference between two Ints
(<->)           :: Int -> Int -> Int
left <-> right  = abs( left - right )

Zie, hier een eigengemaakte operator welke het verschil tussen twee integers oplevert. We kunnen deze vervolgens aanroepen met 5 <-> 7. De stappen om een eigen operator te schrijven zijn niet erg verschillend als die van een functie met twee parameters.
Eerst schrijf je de signature net als bij een functie, echter je schrijft de naam tussen haakjes op. Vervolgens schrijf je de Implementatie met aan de linkerkant de operator tussen de parameters.

Zoals je in het bovenstaande voorbeeld ziet, bestaan de namen van operatoren uit tekens in plaats van letters. De volgende tekens mogen gebruikt worden in het maken van operatoren
code:
1
: # $ % & * + - = . / \ < > ? ! ? @ ^ |

Reeds gereserveerd zijn:
code:
1
:: = .. -- @ \ | <- -> ~ =>


Omdat operatoren en functies met < 3 parameters zo veel op elkaar lijken, is er een manier om een functie als operator te schrijven en vice versa. Dit hebben we eigenlijk al gebruikt bij het definiëren van de operator <->, in de signature. Dit was nodig omdat een operator opzich geen expressie is. Een functienaam is dat wel.
Om een operator als functie te schrijven gebruik je dus haakjes. Andersom schrijf je backticks ` ` om een functienaam, om hem als operator te gebruiken.
code:
1
2
3
4
5
6
7
8
9
10
11
-- Geldige expressie
7 `diff` 10

-- Ook geldig
(<->) 7 10

-- Eveneens geldig, maar best wel onnuttig
(`diff`) 7 10

-- Niet geldig, geen functie met < 2 parameters
4 `discriminant` 4 10


Prioriteiten van operatoren
Op de basisschool en in het vervolg onderwijs zijn wij reeds geconfronteerd met prioriteiten. Zo hebben we daar moeten leren dat 3 + 7 x 10 73 geeft en niet 100. Kortom maal heeft een hogere prioriteit dan plus en daarom wordt 7 x 10 eerst uitgerekend.
We hebben net gezien dat we onze eigen operatoren kunnen maken, dan zouden we deze dus ook een prioriteit moeten geven toch? Nou, moeten is wat sterk uitgedrukt, we hebben immers net een operator gemaakt zonder een prioriteit op te geven, maar het is vaak wel handig.
Neem nou de situatie van onze mooie operator <->. Als we de de expressie 10 <-> 7 * 10 invoeren in Hint, dan krijgen we uitkomst 30.
30!? Ja 30, want hoewel onze expressie niet meer is dan een |10 - 7 * 10| komt er toch niet 60 uit, zoals Meneer van Dale ons altijd vertelde. Hoe kan dat?
Het is eigenlijk heel simpel. Door geen prioriteit te definieren hebben we impliciet de allerhoogste prioriteit gegeven aan onze operator. Zoals we zagen, is dat niet echt handig voor een veredelde min. Vandaar dat we nu een definiëren gaan definieren voor onze operator.

Prioriteiten in Haskell zijn verdeeld in levels met een nummer. Hoe hoger het nummer van het level, hoe hoger de prioriteit van de operator. De volgende lijst van operatoren en bijbehorende prioriteit is te vinden in de Prelude.hs file
code:
1
2
3
4
5
6
7
8
9
10
11
infixr 9  .
infixl 9  !!
infixr 8  ^, ^. -- , **.
infixl 7  *, *., `quot`, `rem`, `div`, `mod`, /., /         
infixl 6  +, -, +., -.                                      
infixr 5  ++
infixr 5 :                                                  
infix  4  ==, /=, <=, <, >, >=, ==., /=., <=., <., >., >=.  
infixr 3  &&
infixr 2  ||
infixr 0  $ --, $!

De operator . zit op het hoogste level en $ op het laagste. Daar ergens tussen in staan +, - etc. Omdat onze operator ongeveer hetzelfde doet als - lijkt het verstandig om hem te positioneren op hetzelfde level als -, dus met prioriteitlevel 6. Echter voordat we dit kunnen doen moeten we eerst nog gaan beslissen of onze operator infix, infixl of infixr gaat worden.

infix
Met infix geef je aan dat de operator op non-associatief is. Dat wil dus zeggen dat a op b op c nooit geschreven mag worden. Altijd moeten haakjes geplaatst worden, dus (a op b) op c of a op (b op c).

infixl
Met infixl geef je aan dat de operator op associeert naar links. Dat betekend dus dat a op b op c impliciet (a op b) op c is. Als je zeker weet dat een operator associatief is (dus bijvoorbeeld + waar de haakjes niet uitmaken) dan is infixl vaak de beste keuze, omdat deze dan iets optimaler is dan infixr. Voorbeelden van infixl operatoren zijn + en -

infixr
Met infixr geef je aan dat de operator op associeert naar rechts. Dat betekend dus dat a op b op c impliciet a op (b op c) is. Een voorbeeld hiervan is ^, zodat 5 ^ 3 ^ 2 gelijk is aan 59.

Naar onze operator <-> kijkend, lijkt me een gelijke werking als - voor <-> een goed idee. Daarmee zou 10 <-> 13 <-> 2 uitkomen op 1. Samenvattend zou onze operator als volgt gedefinieerd kunnen worden.
code:
1
2
3
4
infixl 6 <->
-- Compute the difference between two Ints
(<->)           :: Int -> Int -> Int
left <-> right  = abs( left - right )

Een test met 10 <-> 7 * 10 geeft inderdaad 60. :)

Conditionele code in functies
Je hebt ondertussen vast al een boel functies gemaakt. Echter deze functies voerderen allemaal altijd dezelfde code uit. Maar wat nou als je iets anders wilt doet als de eerste parameter een even getal is of een error wilt genereren als de list leeg is? Daarvoor gaan we nu duiken in de wereld van de conditionele code :)
Conditionele code is er in 4 smaken in Helium. Ik zal er hieronder 3 bespreken: De guards, de if-then-else en pattern matching.

Guards
Guards... dat zijn toch van die ventjes die dagen voor een poort staan te wachten om ervoor te zorgen dat geen ongewilde bezoekers binnensluipen? Ja, inderdaad en zo kan je ze ook zien in Helium :) Een guard is een expressie welke een boolean op zal leveren. Als deze expressie True oplevert, dan mag het programma de code bewaakt door de guard uitvoeren. Als de uitkomst False is, dan krijgt het programma geen toegang.
Guards worden als volgt genoteerd in Heliumfuncties.
code:
1
2
3
4
func a b c    | guard_1 a b = code_1
              | guard_2 b a = code_2
              | guard_3 c a = code_3
              | otherwise   = code_4

Schematisch gezien krijg je dus eerst de functienaam + parameters. Daarna volgt een | en direct daarachter de eerste guard. Een guard kan zowel een functieaanroep zijn als een parameter van de functie zelf. Hierna volgt de = en de code die normaal achter de functie zou staan.
Voor elke extra guard wordt toegevoegd voeg je op de volgende regel een weer een | en guard toe, met bijbehorende code. Voor alle gevallen die niet bij de guard zijn afgevangen kun je er voor kiezen om een guard genaamd 'otherwise' in te voegen.
Let er trouwens op dat Helium de guards een voor een zal afgaan. Hij zal eerst guard_1 proberen, dan guard_2 enz. Als je dus 'otherwise' bovenaan zet, zal altijd de code achter die guard uitgevoerd worden.

if-then-else
if-then-else zit zo'n beetje in elke programmeertaal. Als de conditie ( functieaanroep of parameter ) achter 'if' als waarde True heeft, dan wordt het deel achter de 'then' uitgevoert. Is de waarde False dan zal de code achter 'else' uitgevoerd worden. Schematisch gezien:
code:
1
2
3
func a b c = if   checkFunc a
             then doSomethingWith b
             else doSomethingElseWith c

Hier zal dus als checkFunc a waar is doSomethingWith b uitgevoerd worden. Als checkFunc a niet waar is, dan zal doSomethingElseWith c uitgevoerd worden.
Simpel, maar krachtig :)

Pattern Matching
Pattern Matching is een iets ander verhaal. Iets minder krachtig, maar wel ontzettend mooi. Ik zal aftrappen met een voorbeeld.
code:
1
2
3
null :: [a] -> Bool
null [] = True
null _  = False

Hier zie je dat de functie null twee maal gedefinieerd is met twee keer verschillende parameters. Een maal met [] en een maal met _. Wat betekent dit?
[] Herkennen we nog van lijsten. [] staat voor de lege lijst, de lijst zonder elementen erin. Als de parameter van null dus de lege lijst is, dan zal de functie evalueren naar True. Maar _ is toch geen lijst? Dat klopt. _ is een wildcard. Vergelijk het maar met 'otherwise' bij Guards, het matched op alles.
Kortom null retourneerd True als de lijst de lege lijst is en anders retourneerd hij False.

Nog een voorbeeld:
code:
1
2
3
4
unwords :: [String] -> String
unwords [] = ""
unwords [w] = w
unwords (w:ws) = w ++ ' ' : unwords ws

De functie unwords accepteert een lijst van Strings en produceert een String, waarbij elk element van de lijst aan elkaar geplakt wordt met een spatie ertussen. ["Hallo", "heren", "en", "dames"] wordt dan "Hallo heren en dames".

Als we dan naar de definitie van de functie gaan kijken, zien we dat deze 3 patterns definieerd: [], [w] en (w:ws). De eerste herkennen we als de lege lijst. In het geval dat de lege lijst de parameter van de de functie is, wordt de lege string terug gegeven ("" dus).
Het tweede geval is [w]. Als je het vergelijkt met het definieren van een lijst, dan is [w] gewoon de definitie van een lijst met één element. Dat is ook precies de betekenis van het pattern [w]. Hierin staat w voor het ene element, welke je in de functie kan benaderen met de naam w :) In het geval dat de lijst parameter van unwords een lijst is met éen element, dan zal deze matchen met de [w] en zal w geretourneerd worden.

Het derde en laatste geval is het geval als de lijst niet leeg is, maar ook niet éen element bevat. Kortom, als de lijst een kop en een staart element heeft. Dit kunnen we verkort schrijven als (x:xs) (waarbij x en xs gekozen namen zijn). x staat voor het kop element en xs zijn de staart elementen, wat een lijst is met alle rest elementen.
Omdat xs zelf ook een lijst is met elementen, kunnen we deze lijst weer gebruiken als parameter voor onze eigen functie en hiermee een recursieve functie schrijven. Dit gebeurt ook in unwords , waarbij xs ook gebruikt wordt als nieuwe parameter voor unwords

Onthoud dat pattern matching zo diep kan gaan als je zelf wilt. Je kunt bijvoorbeeld ook een patroon maken voor het geval de parameter een lijst is van lijsten met een lege lijst op de kop
code:
1
2
voorbeeld               :: [[String]] -> Bool
voorbeeld ([]:xs)       = True


Wanneer wat?
Pattern matching wordt gebruikt voor onderscheid van types, terwijl if/else gebruikt wordt voor uitkomsten van functies op waardes. In ieder geval moet je zelf maar kijken wat je het fijnst vindt in welke situatie :)

Iteratie
In de wiskunde kennen we Iteratie. Dat is het herhaaldelijk een functie op een waarde toepassen totdat hij aan een bepaald criticum voldoet. We kunnen bijvoorbeeld kijken welke macht van 2 het eerst over de 1000 komt.
code:
1
until (>1000) (2*) 2
Dit geef inderdaad als antwoord 1024, wat we allemaal al wisten natuurlijk :P

We zien in de code twee onbekende dingen.
• until
• (>1000) en (2*)
Ik zal alleen until bespreken dit keer, de volgende uitgave ;) komen de functies (>1000) en (2*) aan bod.

Until is de juist hierboven besproken vorm van iteratie. Het neemt 3 parameters aan. De eerste parameter is een functie van ( a->Bool ) welke de controle functie is. Als deze functie True oplever, dan stopt until met het uitvoeren van de iteratie.
De tweede parameter, een functie van ( a->a ) is de functie die elke iteratie op de waarde wordt uitgevoerd en welke de beginwaarde voor de volgende iteratie oplevert.
De laatste parameter, een waarde, is de startwaarde van de eerste iteratie.

Let op dat deze functie ook op lijsten kan werken. Hier een voorbeeld die elementen van de lijst weg gooit, totdat de lijst 5 elementen lang is of korter
code:
1
2
3
4
5
6
-- return true if the list is shorter or equal in length
-- than the given number            
lengthCheck             :: [a] -> Int -> Bool
lengthCheck list num    = length list <= num

until (`lengthCheck` 5) tail [1,2,3,4,5,6,7,8,9,0]

Echter, vaak is het gebruik van until op lijsten niet nodig. Hier zijn vaak speciale lijst functies voor die stukken beter werken.

Functies op lijsten
Heel vaak komt het voor dat we over lijsten willen lopen. We willen dan elk element van een lijst hebben om er een bewerking op te doen, erin te zoeken, onjuiste waardes filteren enzovoorts.

In imperatieve talen zou je dan al snel geneigd zijn om te komen met for loops om met een tellertje de lijst langs te lopen. Nu bestaan for loops niet in functionele talen, dus hoe gaan we dat aanpassen? Met een functie natuurlijk ;)

Binnen functionele talen heb je 2 hele belangrijke functies, die eigenlijk veel van het vuile werk opknappen. Dit zijn:
• map
• filter

map
Map is een functie, welke een functie als parameter heeft en een lijst en vervolgens de functie toepast op alle elementen van de lijst. Map is in Helium als volgt gedefinieerd:
code:
1
2
3
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

Als we eerst kijken naar de signature zien we dat map een lijst op zal leveren, die niet hetzelfde type hoeft te zijn als de input. Dat is afhankelijk van de functie. Stel de funtie is een functie van ( Int -> Bool ) dan zal map een lijst van Bool's opleveren bij input van een lijst van Int's.
Kijkend naar de implementatie zien we dat map gebruik maakt van pattern matching. Het eerste patroon is de vertrouwde lege lijst. Map kan geen functie toepassen als er geen elementen zijn, dus retourneerd hij de lege lijst.
Het tweede geval is als de lijst niet leeg is. De head van de lijst wordt van de lijst afgeplukt en x genoemd door het patroon, de rest van de lijst wordt in xs gestopt. Vervolgens wordt de functie op x toegepast en roepen we map weer aan op xs.

Kan dat zomaar? In een functie zichzelf aanroepen? We hebben het er bij de pattern match heel kort over gehad en ja dat kan ;) Wat we meestal doen is de rest van de lijst pakken en daarop de functie nog een keer op uitvoeren. Omdat de rest elke keer kleiner wordt, gaan we ooit bij ons niet recursieve geval ( de lege lijst ) belanden, waar de recursie ophoudt.
Een voorbeeld; We roepen map aan op de lijst [1,2,3] en gebruiken de functie even als parameter voor map.
• De eerste maal is de lijst niet leeg en wordt de head van de lijst afgehaald, het getal 1. Daar voeren we de functie op uit, welke False als resultaat geeft. Vervolgens geven we de lijst [2,3] mee aan map.
• De tweede keer is de lijst nog niet leeg en halen we wederom de head van de lijst, dit keer is dat 2. Daar voeren we even op uit en dit levert True op. We roepen map weer aan met ons restant [3]
• De lijst is weer niet leeg, het bevat één element, namelijk 3. We voeren even uit op 3 en krijgen False. We roepen map weer aan op de rest, dit keer is dat []
• De lijst is dit keer leeg. We retourneren de lege lijst.

We zetten dus telkens het antwoord van de functie aangeroepen op de head op kop van wat onze recursieve aanroep gaat retourneren. Dit komt in ons voorbeeld neer op False : True : False : [] wat gelijk staat aan [False, True, False]

Map is dus een functie om elk element van een lijst langs te lopen en daar een functie op toe te passen. Als je een functie kunt omschrijven met 'voor elk element in de lijst.....' ga dan direct aan map denken :)

filter
Filter is, net als map, een functie welke bedoeld is om alle elementen van een lijst langs te gaan. In plaats van dat een functie wordt toegepast op alle elementen, voert filter een functie uit op het element welke een Bool oplevert. Als het resultaat True is, dan komt het element in het antwoord, anders wordt het eruit gefiltert.
Bijvoorbeeld filter even [1..10] zal alle even elementen van 1 t/m 10 opleveren ( [2,4,6,8,10] )

Een derde functie zal binnenkort volgen :)

Vraagstukken en oefeningen

Probeer eens de volgende vraagstukken op te lossen.

• Welke van de volgende functienamen zijn valide: func, 1func, _func, func1, func_1, f1, f, f#. Waarom wel/niet
• Maak een operator welke een 'normale' deling op integers specificeert. Bijvoorbeeld 52 geeft 2.5. Geef de operator ook een goede prioriteit en associatie.
• Maak een functie die het aantal elementen telt in een lijst die aan een bepaalde conditie voldoen. De signature is
code:
1
 countMatching :: ( a -> Bool ) -> [a] -> Int
. Voorbeeld werking: countMatching even [1..10] levert 5 op.
• Maak een functie waarin je kijkt of een String in een lijst van Strings voorkomt. Return een boolean met de waarde
• Veralgemeen bovenstaande functie, zodat je kunt kijken of een element in een lijst van elementen staat.
• Maak een functie waarmee je kan kijken of alle elementen in een lijst ook in een andere lijst zitten. Je kunt hier van bovenstaande functie handig gebruik maken.

Antwoorden vind je hier maar probeer ze eerst zelf te maken :) Als je totaal andere antwoorden hebt, post ze hier, of mail/icq me en we bekijken ze :) Misschien zijn ze een stuk beter als de mijne ;)

In ieder geval bedankt voor het lezen :) Kritiek en mededelingen mogen natuurlijk naar mijn mail, in dit topic of naar mijn ICQ# :)
Ik wens iedereen succes met deze tutorial :)

[ Voor 108% gewijzigd door Glimi op 03-06-2003 16:59 ]


  • MisterData
  • Registratie: September 2001
  • Laatst online: 16-05 23:29
_/-\o_

Verheugde me al op het tweede deel, nu de opgaves nog ff maken :)

  • koli-man
  • Registratie: Januari 2003
  • Laatst online: 13-05 14:28

koli-man

Bartender!!!!

Wordt deze taal ook in het "bedrijfsleven" gebruikt en zo ja, wat voor een soort applicaties wordt dan van deze taal gebruik gemaakt?

Hey Isaac...let's go shuffleboard on the Lido - deck...my site koli-man => MOEHA on X-Box laaaiiiff


Verwijderd

koli-man schreef op 03 June 2003 @ 08:42:
Wordt deze taal ook in het "bedrijfsleven" gebruikt en zo ja, wat voor een soort applicaties wordt dan van deze taal gebruik gemaakt?
Daar staat hier wel wat over in: F#, functioneel programmeren in .NET

  • MachoM
  • Registratie: April 2003
  • Laatst online: 21-11-2025
lol heb je dit uit een dictaat gehaald, of ben je echt zo lang bezig geweest ;)

Verwijderd

Handige opfris cursus :)

Het meeste wist ik al wel, maar dat Haskell vergeet je ook direct als je er even niet meer mee hebt gewerkt...

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Idd, ik moest hier net iemand vragen hoe flip ook alweer in Haskell heet (flip dus ;) ).

Goed en nobel werk!

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • GrimaceODespair
  • Registratie: December 2002
  • Laatst online: 22:54

GrimaceODespair

eens een tettenman, altijd ...

Glimi schreef op 02 June 2003 @ 15:30:
• Operatoren hebben altijd maximaal 2 operatoren
[zeikmodus]laatste 'operatoren' = 'operands'[/zeikmodus]

Maar verder: puike tutorial. Weet niet of er een discussie aan voorafgegaan is, maar lijkt me toch een leuke link voor in de FAQ (als ie daar nog niet staat; ik heb hem iig nog niet gevonden)

Wij onderbreken deze thread voor reclame:
http://kalders.be


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

Topicstarter
(overleden)
koli-man schreef op 03 June 2003 @ 08:42:
Wordt deze taal ook in het "bedrijfsleven" gebruikt en zo ja, wat voor een soort applicaties wordt dan van deze taal gebruik gemaakt?
Heel spaarzaam eigenlijk. Ik geloof dat yahoo shops LISP zijn, maar meer zou ik ook niet zo 1-2-3 kunnen bedenken :)
MachoM schreef op 03 June 2003 @ 09:21:
lol heb je dit uit een dictaat gehaald, of ben je echt zo lang bezig geweest ;)
Het heeft ongeveer een uur of 10 gekost. De precieze regels van een functie heb ik wel uit de reader geleend, maar dat had net zo goed van de haskell site kunnen zijn ;)
Verder alles uit m'n eigen kop :)
GrimaceODespair schreef op 03 June 2003 @ 10:36:
[zeikmodus]laatste 'operatoren' = 'operands'[/zeikmodus]
Niets zeikmodus :) Danku voor de opmerking, ik pas het gelijk aan :)
Maar verder: puike tutorial. Weet niet of er een discussie aan voorafgegaan is, maar lijkt me toch een leuke link voor in de FAQ (als ie daar nog niet staat; ik heb hem iig nog niet gevonden)
Hij zal er echt wel komen hoor. De nieuwe FAQ update staat toch geplanned samen met een ASP stuk en een 'Wat moet ik kosten stuk' dus dat zal wel binnekort komen :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 20:49

.oisyn

Moderator Devschuur®

Demotivational Speaker

Glimi schreef op 02 June 2003 @ 15:30:
Omdat operatoren en functies met < 2 parameters zo veel op elkaar lijken
< 3 of <= 2, maar niet < 2 ("minder dan 2") ;)

.edit: kun je ook een Orbb tutorial voor mij typen? :P

[ Voor 12% gewijzigd door .oisyn op 03-06-2003 12:51 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MachoM
  • Registratie: April 2003
  • Laatst online: 21-11-2025
Glimi schreef op 03 June 2003 @ 11:54:
[...]

Het heeft ongeveer een uur of 10 gekost. De precieze regels van een functie heb ik wel uit de reader geleend, maar dat had net zo goed van de haskell site kunnen zijn ;)
Verder alles uit m'n eigen kop :)

[...]
10 uur!!! respect _/-\o_

  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

Topicstarter
(overleden)
.oisyn schreef op 03 June 2003 @ 12:48:
< 3 of <= 2, maar niet < 2 ("minder dan 2") ;)
Fixed. Thanx :)
.edit: kun je ook een Orbb tutorial voor mij typen? :P
Als jij ff balanceert wat ik in één tut kan stoppen wil ik dat best doen :)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik vraag me af of die tutorials van je nu echt zo duidelijk zijn dat er helemaal geen vragen over zijn :? Ik zou graag vragen zien :+ (technische, geen meta vragen).

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

Topicstarter
(overleden)
mbravenboer schreef op 03 juni 2003 @ 17:32:
Ik vraag me af of die tutorials van je nu echt zo duidelijk zijn dat er helemaal geen vragen over zijn :? Ik zou graag vragen zien :+ (technische, geen meta vragen).
Of...... niemand leest ze ;)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Ok dan, technisch vraagje; hoe zit het met functies van functies? map lijkt zo'n functie, maar volgens deel1 is een functie geen type, terwijl functieparameters wel types moeten hebben :?

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
Vraagstuk:
Kan je met Haskell een cyclistisch datastructuur maken?
a) Wat versta je onder een cyclistisch datastructuur
b) Is dit wel of niet mogelijk onder Haskell, of een functionele taal. Denk hierbij o.a. aan updates, eindigheid van de structuur en evtueel ook strictness en puurheid.

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
Ok dan, technisch vraagje; hoe zit het met functies van functies? map lijkt zo'n functie, maar volgens deel1 is een functie geen type, terwijl functieparameters wel types moeten hebben :?
Een functie is geen type, maar een functie heeft wel een type. Verder is een functie een first class object, dus kan als parameter van functies gebruikt worden. Verder kunnen functies partieel geparametriseerd worden. Wanneer je een parameter van een functie invult ontstaat een 'nieuwe' functie (met één parameter minder). Als er geen parameters meer over zijn dan heb je uiteraard het resultaat van de functie in handen.

[ Voor 3% gewijzigd door Infinitive op 04-06-2003 00:07 ]

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

Topicstarter
(overleden)
MSalters schreef op 03 June 2003 @ 23:31:
Ok dan, technisch vraagje; hoe zit het met functies van functies? map lijkt zo'n functie, maar volgens deel1 is een functie geen type, terwijl functieparameters wel types moeten hebben :?
Mjah de types van deel 1 wou ik in deel 3 nog maar eens helemaal overhoop gooien ;)
Ik moet inderdaad ook nog gaan bespreken dat functies ook gewoon first-class objecten zijn en dus ook overal te gebruiken zijn.
Zo is dit bijvoorbeeld mogelijk
code:
1
map (sin . ) [ cos, tan ]
Wat je een lijst van 2 functies zal geven.
Een functie past eerst de cosinus toe op een Float en daarna de Sinus
De andere past eerst de tangens toe op een Float en daarna de Sinus (zoals je raad is . dus de functie compositie operator)

Verder moet ik ook nog uitleggen over currying en functie associatie ed.
Kortom, vind je het erg dat ik dat uitgebreid in tutorial 3 of later ga uitleggen :)

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:07
MSalters schreef op 03 June 2003 @ 23:31:
Ok dan, technisch vraagje; hoe zit het met functies van functies? map lijkt zo'n functie, maar volgens deel1 is een functie geen type, terwijl functieparameters wel types moeten hebben :?
Een function signature vormt inderdaad ook een (samengesteld) type en map heeft inderdaad een parameter van zo'n type (zoals je al uit de voorbeeldcode afgeleid had). Je kunt dit echter ook als een speciaal soort algebraïsch datatype beschouwen (maar dat werd ook niet genoemd, geloof ik). Het overzicht uit deel 1 van de tutorial was (mijns inziens) dus incompleet.
Infinitive schreef op 03 June 2003 @ 23:57:
Vraagstuk:
Kan je met Haskell een cyclistisch datastructuur maken?
a) Wat versta je onder een cyclistisch datastructuur
b) Is dit wel of niet mogelijk onder Haskell, of een functionele taal. Denk hierbij o.a. aan updates, eindigheid van de structuur en evtueel ook strictness en puurheid.
Hmm, misschien interessanter om dit te bewaren voor na deel 3, wanneer algebraïsche datatypen behandeld zijn. In principe is een cyclische structuur geen probleem, maar wat erg lastig is, is het ontbreken van enige identiteit van closures, wat het aflopen/bijwerken van cyclische structuren nogal moeilijk maakt. Die identiteit kun je zelf wel toevoegen, maar dat doet toch weer een beetje afbreuk aan het principe.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Glimi: Verder moet ik ook nog uitleggen over currying en functie associatie ed.
Kortom, vind je het erg dat ik dat uitgebreid in tutorial 3 of later ga uitleggen :)
Dat lijkt me inderdaad nuttig ja. Uitleggen wat de rol van functies nu eigenlijk echt is komt voor een groot deel op deze onderwerpen neer.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment

Pagina: 1