Skip to content

Latest commit

 

History

History
359 lines (346 loc) · 11.7 KB

meet_elm_ita.org

File metadata and controls

359 lines (346 loc) · 11.7 KB

Introduzione a Elm

1 Introduzione

1.0.1 Meet Elm

questa presentazione e il codice si trova liberamente accessibile in

http://github.com/noiseOnTheNet/meet_elm

2 Una semplice Form

2.0.1 Elm Architecture: Una semplice Form

Dalla versione 0.17 of Elm, il linguaggio precedente è stato notevolmente semplificato rimuovendo l’infrastruttura “reattiva” per un pattern meno generale ma piú chiaro

Iniziamo questo viaggio con due bottoni che possono incrementare o decerementare un valore intero

2.0.2 Elm Architecture: La funzione Main

la funzione main accetta un record che contiene quattro funzioni: andremo a conoscerle una per una

main : Program Never Model Msg
main =
    Html.program
        { init = init
        , subscriptions = subscriptions
        , update = update
        , view = view
        }

La segnatura di tipo significa: questo è un Program che non ha un imput a startup, ha uno stato interno di tipo Model che viene modificato da eventi di tipo Msg

2.0.3 Elm Architecture: il Model

questo tipo rappresenta lo stato interno dell’applicazionr

type alias Model = Int

Gli alias sono utili per leggere i codice ed i messaggi di errore

Cominciamo con un modello semplice che modificheremo in seguito

2.0.4 Elm Architecture: la Init

dobbiamo inizializzare lo stato del sistema quando viene avviato

init : ( Model, Cmd Msg )
init = ( 0, Cmd.none )

La funzione init restituisce una coppia il cui primo elemento è lo stato dell’applicazione e il secondo rappresenta una “azione” da compiere (per esempio mandare un messaggio al server)

Iniziamo con stato 0 e nessun effetto.

Il tipo Cmd è parametrizzato, ed accetta un altro tipo come parametro

2.0.5 Elm Architecture: i messaggi

questo tipo di dato rappresenta i segnali asincroni che vengono mandati all’applicazione

type Msg = Increment | Decrement

In questo esempio utilizziamo uno union type che in questo caso ha soltanto due costruttori vuoti; in pratica il tipo puó avere solo due valori.

2.0.6 Elm Architecture: la Update

questa funzione restituisce lo stato aggiornato dopo l’arrivo di un segnale

update : Msg -> Model -> ( Model, Cmd Msg )
update message model = 
    case message of
        Increase ->
            ( model + 1, Cmd.none )

        Decrease ->
            ( model - 1, Cmd.none )

Il tipo di questa funzione dice che ci aspettiamo un evento come primo valore passato alla funzione e lo stato corrente come secondo; il valore restitutito è una coppia che contiene lo stato modificato e un “effetto” da eseguire.

2.0.7 Elm Architecture: la View

questa funzione mostra la pagina a partire dal modello

view : Model -> Html Msg
view model =
    div []
        [ button [ onClick Increase ] [ text "Add 1" ]
        , div [] [ text <| "Buy " ++ (toString model) ++ " bananas" ]
        , button [ onClick Decrease ] [ text "Remove 1" ]
        ]

2.0.8 Elm Architecture: update Index.html

è necessario un piccolo cambiamento nell’html per proseguire

<script type="text/javascript">
  var d = document.getElementById('main');
  Elm.Form.embed(d);
</script>

2.0.9 Estendere la Form

ora aggiungeremo alla vista un campo password e la sua conferma; vogliamo poter segnalare all’utente la qualità della password (forte o debole) e se entrambe i campi corrispondono

2.0.10 Estendere la Form: Aggiungere più Widgets

anzitutto aggiungiamo un campo password nella vista e aggiungiamo un evento per rilevare il cambiamento

	div  []
         [ div []
	      [ label [ for "pass1" ] [ text "type your password" ]
	      , input [ id "pass1"
                 , onInput UpdatePass1
                 , type_ "password"
                 , value model.pass1
                 ]
                 []
	      ]
         , -- some thing for pass2
         ]

2.0.11 Estendere la Form: Aggiungere più Messaggi

I due messaggi vengono aggiunti al tipo unione per considerare i cambiamenti in entrambe i campi password

type Msg
    = Increase
    | Decrease
    | UpdatePass1 String
    | UpdatePass2 String

the new messages now carry a value of type string

2.0.12 Estendere la Form: Estendere lo Stato

Per contenere maggiori informazioni estendiamo lo stato trasformandolo in un record

type alias Model =
    { counter : Int
    , pass1 : String
    , pass2 : String
    }

init : ( Model, Cmd Msg )
init =
    ( { counter = 1
      , pass1 = ""
      , pass2 = ""
      }
    , Cmd.none
    )

2.0.13 Estendere la Form: Estendere l’aggiornamento

Se provassimo a compilare ora otterremmo un errore dal comando case poichè il pattern matching non è completo; questi nuovi casi dimostrano anche come gestire il pattern matching e la decomposizione dei valori

UpdatePass1 value ->
        ( { model
            | pass1 = value
          }
        , Cmd.none
        )

UpdatePass2 value ->
        ( { model
            | pass2 = value
          }
        , Cmd.none
        )

2.0.14 Estendere la Form: Estendere il modello

Vorremmo restituire all’utente una informazione relativamente al livello di sicurezza: possiamo catturare questo concetto in un tipo

type PassSecurity
    = Weak
    | Minimal
    | Good

e metterlo nel nostro modello

type alias Model =
    { counter : Int
    , pass1 : String
    , pass2 : String
    , passMatching : Bool
    , passSecurity : PassSecurity
    }

2.0.15 Estendere la Form: Extending the code setup

in our init code we add initial values

, pass2 = ""
, passMatching = False
, passSecurity = Weak
}

2.0.16 Completare la vista: livello di sicurezza

ora possiamo mostrare il valore

, div []
    [ label [ for "pass1" ] [ text "type your password" ]
    , input
        [ id "pass1"
        , onInput UpdatePass1
        , type_ "password"
        , value model.pass1
        ]
        []
    , text <| "Security " ++ (toString model.passSecurity)
    ]
, hr [] []

2.0.17 Completare la vista: corrispondenza delle password

mostriamo anche con i colori se le password corrispondono

, div []
    [ label [ for "pass2" ] [ text "retype your password" ]
    , input
        [ id "pass2"
        , onInput UpdatePass2
        , type_ "password"
        , value model.pass2
        ]
        []
    , let
        ( message, color ) =
            if model.passMatching then
                ( "Matching", "green" )
            else
                ( "Not Matching", "red" )
      in
        div [ style [ ( "color", color ) ] ] [ text message ]
    ]

2.0.18 Completare l’update: logica sulla sicurezza

per esempio possiamo definire il livello di sicurezza basandoci solo sulla lunghezza della password

UpdatePass1 value ->
    let
        passLength =
            String.length value

        security =
            if passLength < 4 then
                Weak
            else
                (if passLength < 6 then
                    Minimal
                 else
                    Good
                )
    in
        ( { model | pass1 = value, passSecurity = security }, Cmd.none )

2.0.19 Completare l’update: corrispondenza password

Possiamo confrontare le password per vedere se corrispondono

UpdatePass2 value ->
    let
        match =
            value == model.pass1
    in
        ( { model
            | pass2 = value
            , passMatching = match
          }
        , Cmd.none
        )

this check must be added on the other case in order to make everything correct

2.0.20 Debugger

Il codice Elm non ha molti dei problemi che si incontrano in javascript, ma questo non sempre basta a garantire il corretto funzionamento di un programma.

Talvolta è necessario poter utilizzare un debugger: è anche divertente da vedere

2.0.21 Debugger: Compiling with debugger option

You can compile the form with the --debug option

elm-make Form.elm --warn --debug --output main.js

this is useful in development: production code should not be compiled in this way

In the page now a new control appears which counts every event recorded

2.0.22 Debugger: Time Travelling

through the debugging interface it is possible to:

  • move to any recorded event and see the internal state while the GUI updates
  • load and save all events list: this is great to report problems and reproduce each step

2.0.23 Takeaways

  • The Type System support refactoring
  • The Purity support debug