Last active
June 12, 2018 07:37
-
-
Save ulve/0e7c9d1ebb539cb0570b473bff63f2c1 to your computer and use it in GitHub Desktop.
Gneric overload
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
Först har vi då en funktion. Den är inte så jäkla återanvändbar. Den tar en lista med strängar | |
och returnerar en lista med strängar | |
-} | |
sayHello :: List String -> List String | |
sayHello Nil = Nil | |
sayHello (name : names) = | |
("Hello, " <> name) : sayHello names | |
-- Den stegar igenom listan med rekursion och lägger till "Hello, " före | |
sayHello ("Katt" : "Hund" : "Fisk" : Nil) | |
--("Hello, Katt" : "Hello, Hund" : "Hello, Fisk" : Nil) | |
{- | |
vi kan ju göra bättre ifån oss. Om "Hello, " inte är hårdkodat så går den ju använda till | |
nått annat i alla fall | |
-} | |
prependAll :: String -> List String -> List String | |
prependAll prefix Nil = Nil | |
prependAll prefix (name : names) = | |
(prefix <> name) : prependAll prefix names | |
-- Coolt då kan man ju göra | |
sayHello = prependAll "Hello, " | |
sayGoodbye = prependAll "Goodby, " | |
-- supersmidigt! | |
{- | |
Men hela den här iden med att man sätter till före? Njaaa vi kan bättre! | |
Hur vore det om man kunde skicka med en funktion som skötte var man la till | |
sakerna? | |
-} | |
tarnsform :: (String -> String) -> List String -> List String | |
transform editFunc Nil = Nil | |
transform editFunc (name : names) = | |
(editFunc name) : transform editFunc names | |
-- Kolla då kan vi göra prepend! | |
prependAll prefix = transform (prefix <> _) | |
-- och även en append! wohoo | |
appendAll suffix = transform (_ <> suffix) | |
{- | |
En sak jag inte gillar är att funktionen bara tar strängar. Vem säger | |
att det alltid är det vi vill ha? nää bättre kan vi! | |
Här har vi alltså generics eller vad man skall säga. val är vår typ | |
och funktionen gäller för alla typer (forall val.) | |
sen har vi en funktion som tar ett val och ger ett val som svar | |
sen en lista med val och slutligen så får vi en lista med val som | |
svar. Det här är ju supergeneriskt! | |
-} | |
transform :: forall val. (val -> val) -> List val -> List val | |
transform editFunc Nil = Nil | |
transform editFunc (first : rest) = | |
(editFunc first) : transform editFunc rest | |
-- Då går ju funktionen använda till det här | |
negateAll :: List Boolean -> List Boolean | |
negateAll = transform negate | |
-- Vi tar alltså en lista med bools och negerar alla värden | |
-- Eller det här | |
addAll :: Int -> List Int -> List Int | |
addAll num = transform (_ + num) | |
-- Vi tar en lista med ints och lägger på ett värde på alla ints | |
{- | |
Men en korkad sak är ju att listan har samma typer på båda sidor. | |
Säg om vi vill kunna transformera med den frånt t.ex. inte till bool | |
hur skulle vi göra då? Jo vi kan göra den mer generisk! | |
här har vi två typ-variabler a och b sen en funktion som går från a | |
till typen b. | |
in tar vi även en lista med a och ger en lista med b | |
nu är vi nära nirvana! | |
-} | |
transform :: forall a b. (a -> b) -> List a -> List b | |
transform editFunc Nil = Nil | |
transform editFunc (first : rest) = | |
(editFunc first) : transform editFunc rest | |
-- Då kan vi göra funktioner som den här | |
formatAll :: List Number -> List String | |
formatAll = transform Number.toString | |
{- | |
Nu har vi en korkad sak kvar. Varför bara listor? | |
Vi skulle vilja ha något som den här | |
transform :: forall f a b. (a -> b) -> f a -> f b | |
alltså vi har någon typ f som i vårt fall är en lista men som | |
lika gärna skulle kunna vara en array eller ett träd? hur gör man det? | |
-} | |
transform :: forall f a b. (a -> b) -> f a -> f b | |
transform transformator transform = ???? | |
-- Nä jag vet inte hur man gör? går det ens? | |
{- | |
Vi kan börja med att plocka ut en del till en egen typ. Det här är ett smart | |
sätt om man ser en signatur dyka upp ofta | |
Här har vi typen Transform med typvariablerna f, a och b | |
-} | |
type Transform f a b = | |
(a -> b) -> f a -> f b | |
-- Då kan vi göra en sån för våra listor! | |
transformList :: forall a b. Transform List a b | |
transformList editFunc Nil = Nil | |
transformList editFunc (first : rest) = | |
(editFunc first) : transformList editFunc rest | |
-- Det som är bra är då att vi kan göra det för andra datatyper | |
transformArray :: forall a b. Transform Array a b | |
-- och | |
transformTree :: forall a b. Transform Tree a b | |
{- | |
Egentligen går det att snygga till. vi kan flytta in a och b in in i | |
definitionen och slippa ha dom som typargument | |
-} | |
type Transform f = | |
forall a b. (a -> b) -> f a -> f b | |
transformList :: Transform List | |
transformList editFunc Nil = Nil | |
transformList editFunc (first : rest) = | |
(editFunc first) : transformList editFunc rest | |
{- | |
Då kan vi göra en funktion som tar en lista eller array och lägger ett | |
till ett nummer på alla poster | |
-} | |
addAll :: forall f. Transform f -> Int -> f Int -> f Int | |
addAll transform num = transform (_ + num) | |
-- Eller vår gamla klassiker say hello | |
sayHello :: forall f. Transform f -> f String -> f String | |
sayHello transform names = transform ("Hello, " <> _) names | |
-- Så för att anropa den så kan man köra | |
sayHello transformList ("Katt" : "Hund" : "Fisk" : Nil) | |
-- och om vi hade en array | |
sayHello transformArray ("Katt" : "Hund" : "Fisk" : Nil) | |
-- Nu finns det ett steg till va. Vi hade velat slippa skicka in vilken | |
-- Transformator som skall användas. För att det skall ske så måste man | |
-- ha en funktion i språket som heter typklasser. Det är nästa steg. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment