Herramientas de usuario

Herramientas del sitio


wiki2:elm

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
wiki2:elm [2020/05/09 08:09]
alfred [Type Aliases]
wiki2:elm [2020/05/16 11:53] (actual)
Línea 43: Línea 43:
 </​code>​ </​code>​
  
 +
 +===== Functional programming concepts =====
 +
 +A **higher order function** is a function that operates with functions in a way that takes a function as an argument, or returns a function.
 +
 +A **combinator function** is a function that only relies on those functions that are passed as arguments.
 +
 +A **curried function** is a function partly applied. For example, having this one:
 +<​code>​
 +getIds users = List.map (\u -> u.userId) users
 +</​code>​
 +
 +We can write it like this:
 +<​code>​
 +getIds = List.map .userId
 +</​code>​
 +
 +In this way ''​getIds''​ returns another function which is a map that will extract the ''​userId''​ paramater from what is passed to the previous function.
 +
 +**Free variables** are those that are not taken from function arguments.
 +
 +A **closure** is a persistent local variable scope. The scope is kept for local variables even after the code execution has moved out of that block. In the next JS code we have an ''​outer''​ function which will return the ''​inner''​ function. The variable ''​a''​ is defined inside ''​outer''​ and has that scope, however, it is accessed when inner is called.
 +<code javascript>​
 +outer = function() {
 +  var a = 1;
 +  var inner = function() {
 +    console.log(a);​
 +  }
 +  return inner; // this returns a function
 +}
 +var fnc = outer(); // execute outer to get inner 
 +fnc();
 +</​code>​
 +
 +In Elm we can achieve a closure returning a function:
 +<​code>​
 +> stringRepeater n = \s -> String.repeat n s
 +<​function>​ : Int -> String -> String
 +> twentyTimesString = stringRepeater 20
 +<​function>​ : String -> String
 +> twentyTimesString "​a"​
 +"​aaaaaaaaaaaaaaaaaaaa" ​
 +</​code>​
 +
 +==== Destructuring ====
 +
 +<​code>​
 +let
 +(firstName, lastName) = ("​John",​ "​Doe"​)
 +in
 +lastName -- Result: Doe
 +
 +-- ... or ... 
 +second (_, snd) = snd
 +second (0, 1) -- Result: 1
 +
 +-- ... or..
 +userName : User -> String
 +userName user =
 +let
 +(User name) = user
 +in
 +String.toLower name
 +
 +-- ... or... 
 +type alias Vector = { x : Int, y : Int }
 +length : Vector -> Float
 +length { x, y } = sqrt <| toFloat <| x^2 + y^2
 +length { x = 1, y = 2 } -- Result: 2.2360
 +length { x = 1, y = 2, z = 3 } -- Error
 +-- To do this:
 +length : { r | x : Int, y : Int } -> Float
 +length { x, y } = sqrt <| toFloat <| x^2 + y^2
 +length { x = 1, y = 2, z = 3 } -- OK
 +-- or
 +type alias Vector r = { r | x : Int, y : Int }
 +length : Vector r -> Float
 +length { x, y } = sqrt <| toFloat <| x^2 + y^2
 +</​code>​
 +
 +==== Pattern matching ====
 +Pattern matching is a mechanism for choosing the branch of code to execute based on the type or value of a given expression.
 +
 +==== Functors, monads and applicatives ====
 +
 +  * Functors are things you can map on
 +  * Monads things you can andThen on 
 +  * Applicatives things you can andMap on
 ===== Basic ===== ===== Basic =====
  
 +==== Records ====
 +
 +Constructing:​
 +<​code>​
 +type alias User = { userId: Int, name: String }
 +User 1 "​John"​
 +</​code>​
 +
 +For each record type alias, the compiler automatically generates a constructor function of the same name. The constructor is a regular function so it can be partially applied:
 +<​code>​
 +User 1
 +</​code>​
 +
 +Extending records in the next two ways:
 +<​code>​
 +type alias GenericNode a = { a | 
 + actualLoops : Int, actualRows : Int,
 + actualStartupTime : Float,
 + actualTotalTime : Float
 + }
 +type alias CteNode = GenericNode
 +
 + nameAlias : String
 + }
 +-- A CteNode is a record with all the fields of GenericNode plus an additional alias field.
 +</​code>​
 +
 +=== Constructing records from another ===
 +<​code>​
 +> type alias A = { a: String, b: Int }
 +> type alias B = { a: String, b: Int }
 +> a : A
 +| a = A "​prueba"​ 666
 +{ a = "​prueba",​ b = 666 } : A
 +> b : B
 +| b = a
 +{ a = "​prueba",​ b = 666 } : B
 +</​code>​
 ==== Type annotation ==== ==== Type annotation ====
  
Línea 120: Línea 246:
 -- Visitor "​kate95"​ : User -- Visitor "​kate95"​ : User
 </​code>​ </​code>​
 +
 +=== Types variable ===
 +
 +When you do not care about the type that is passed. In the next example the ''​List''​ passed to ''​List.length''​ can be a ''​List String'',​ ''​List Int''​...
 +<​code>​
 +> List.length
 +<​function>​ : List a -> Int
 +</​code>​
 +
 +However it can restrict the output. With ''​List.reverse''​ we know that we are going to obtain a ''​List''​ with the same type as it was passed on the first instance.
 +<​code>​
 +> List.reverse
 +<​function>​ : List a -> List a
 +> List.reverse [ "​a",​ "​b",​ "​c"​ ]
 +["​c","​b","​a"​] : List String
 +> List.reverse [ True, False ]
 +[False,​True] : List Bool
 +</​code>​
 +
 +=== Recursive types ===
 +<​code>​
 +type Tree a
 +  = Empty
 +  | Node a (List (Tree a))
 +</​code>​
 +
 +=== Special types ===
 +  * number (Int, Float)
 +  * appendable (String, Lists)
 +  * comparable (Int , Float , Char , String , lists, and tuples)
 +
 +Consider ''​Set.map''​ from the Elm core library:
 +<​code>​
 +map : (comparable -> comparable2) -> Set comparable -> Set comparable2
 +map func set = 
 +</​code>​
 +This function produces a new set (in other words: list) from the input set by applying ''​func''​ to elements of ''​set''​. Since set elements have to be comparable, ''​func''​ takes a value of a ''​comparable''​ type as its argument, and it also has to return a value of a ''​comparable''​ type. 
 +
 +However, the input and output types are not necessarily the same, so it doesn’t make sense to write ''​(comparable -> comparable)''​. ​ In order to allow these sorts of functions, number, appendable and comparable can be suffixed with an alphanumeric sequence without changing their meaning.
 +
 +=== Phantom types ===
 +
 +Those types that contain variables that are not used on their constructors:​
 +<​code>​
 +type Unit tag value = Unit value
 +</​code>​
 +
 +It can be used like this:
 +<​code>​
 +type KmTag = KmTag
 +type MileTag = MileTag
 +km : number -> Unit KmTag number
 +km = Unit
 +mile : number -> Unit MileTag number
 +mile = Unit
 +</​code>​
 +These types use different tags. Now we can restrict value types; for example, when a function expects a KmTag and we pass a mile to it, then an error will raise.
 +<​code>​
 +showKm : Unit KmTag Float -> String
 +showKm (Unit d) = String.fromFloat d
 +distance = mile 12.34
 +s = showKm distance -- this raises an error
 +</​code>​
 +
 +Use cases:
 +  * When you want to distinguish between values which have the same runtime representation,​ and you have a shared set of operations you want to perform on all the different types of these values.
 +  * "hen you want to use a particular runtime representation for reasons of performance or memory use, but still want compile-time enforcement of the semantics of different types.
 +
  
 ==== Type Aliases ==== ==== Type Aliases ====
wiki2/elm.1589011774.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)