Skip to content

Instantly share code, notes, and snippets.

@ulve
Last active June 12, 2018 07:37
Show Gist options
  • Save ulve/0e7c9d1ebb539cb0570b473bff63f2c1 to your computer and use it in GitHub Desktop.
Save ulve/0e7c9d1ebb539cb0570b473bff63f2c1 to your computer and use it in GitHub Desktop.
Gneric overload
{-
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