Track
/
Elm
Elm
/
Esercizi
/
Seguace della moda
Seguace della moda

Seguace della moda

Esercizio di apprendimento

Introduzione

Record

I record sono strutture dati che raggruppano insieme informazioni correlate con delle etichette. Sono simili agli oggetti in JavaScript o Java, o alle struct in C o Rust, ma con alcune differenze importanti.

Creare i record

I record si creano con le parentesi graffe ({}) e i loro elementi sono separati da virgole.

firefly =
    { name = "Firefly"
    , creator = "Joss Whedon"
    , episodes = 14
    }

Anche il tipo di un record si definisce con una sintassi simile, tranne per il fatto che i segni di uguale = vengono sostituiti dai segni di due punti :.

firefly : { name : String, creator : String, episodes : Int }
firefly =
    { name = "Firefly"
    , creator = "Joss Whedon"
    , episodes = 14
    }

Ripetere queste definizioni di tipo è scomodo, quindi usare un type alias per condividere la definizione è un idioma comune.

type alias TvSeries =
    { name : String
    , creator : String
    , episodes : Int
    }

firefly : TvSeries
firefly =
    { name = "Firefly"
    , creator = "Joss Whedon"
    , episodes = 14
    }

L'alias di tipo fornisce anche automaticamente una funzione costruttrice per il record. Questo a volte sorprende, dato che in Elm le funzioni devono iniziare con una lettera minuscola, ma i costruttori di tipo sono una delle eccezioni.

firefly : TvSeries
firefly = TvSeries "Firefly" "Joss Whedon" 14

Accedere ai campi di un record

Il modo principale per accedere al valore di un campo di un'istanza di un record è usare la notazione con il punto, come firefly.creator. Il compilatore Elm supporta anche speciali funzioni di accesso che iniziano con un punto ., come .creator, che funzionano su qualsiasi record con un campo con quel nome. Questa è la seconda eccezione alla regola secondo cui le funzioni devono iniziare con una lettera minuscola. In realtà le funzioni definite dall'utente devono iniziare con una lettera minuscola, ma i due esempi che abbiamo appena visto sono generati dal compilatore, non dal programmatore.

firefly : TvSeries
firefly =
    { name = "Firefly"
    , creator = "Joss Whedon"
    , episodes = 14
    }

firefly.name
    --> "Firefly"

.creator firefly
    --> "Joss Whedon"

I record si possono anche destrutturare nelle associazioni, usando il record pattern matching. La destrutturazione funziona con qualsiasi record che abbia campi con i nomi in questione.

episodesCount : TvSeries -> Int
episodesCount { episodes } =
    episodes

complicatedCopy : TvSeries -> TvSeries
complicatedCopy show =
    let
        { name, creator } = show
    in
    { name = name
    , creator = creator
    , episodes = episodesCount show
    }

Aggiornare i record

I record sono immutabili, come tutto in Elm, quindi una volta definito un record, i valori dei suoi campi non possono mai cambiare. Esiste una sintassi speciale per creare una copia di un record esistente cambiando uno o più campi. Questa sintassi usa il simbolo pipe | per distinguere il record originale dai campi che cambieranno, come in { oldRecord | field1 = newValue }.

firefly : TvSeries
firefly =
    { name = "Firefly"
    , creator = "Joss Whedon"
    , episodes = 14
    }

updatedFirefly : TvSeries
updatedFirefly =
    { firefly | creator = "J Whedon", episodes = 15 }

Confrontare i record

Elm usa l'[uguaglianza strutturale][equality], il che significa che due istanze dello stesso record con valori identici sono uguali.

firefly1 = TvSeries "Firefly" "Joss Whedon" 14
firefly2 = TvSeries "Firefly" "Joss Whedon" 14

firefly1 == firefly2
    --> True

Record estensibili

Elm supporta anche la tipizzazione strutturale, il che significa che se una funzione richiede un record con un campo x e un campo y, funzionerà con qualsiasi record che abbia quei campi, come punti 2D, punti 3D, astronavi e così via. Quei tipi di record hanno una pipe | nella loro definizione, come { a | x : Float, y : Float }, e nella terminologia di Elm sono chiamati «record estensibili». Attenzione alla differenza tra una pipe | in una definizione di tipo, che è una definizione di record estensibile ({ a | x : Int }), e una pipe | in un'istanza di record vera e propria, che significa che stiamo aggiornando alcuni campi di quel record.

point2d = { x = 1, y = 2 }
point3d = { x = 3, y = 4, z = 7 }

.x point2d --> 1
.x point3d --> 3

length : { a | x : Float, y : Float } -> Float
length vector =
    sqrt (vector.x * vector.x + vector.y * vector.y)

length point2d --> 2.236068
length point3d --> 5

translateX : { a | x : Float } -> { a | x : Float }
translateX vector =
    { vector | x = vector.x + 1 }

translateX point2d --> { x = 2, y = 2 }
translateX point3d --> { x = 4, y = 4, z = 7 }

Istruzioni

In questo esercizio sei un grande appassionato di sport e hai appena scoperto una passione per il basket NBA. Dato che sei nuovo al basket NBA, ti stai addentrando nella storia della NBA, tenendo traccia di squadre, allenatori, le loro statistiche di vittorie e sconfitte e confrontandole tra loro.

Siccome non hai ancora una squadra del cuore, svilupperai anche un algoritmo per capire se tifare per una squadra in particolare. Hai sette attività per aiutarti a sviluppare il tuo algoritmo proprietario tifa-per-una-squadra.

1. Definisci il modello

Definisci l'alias di tipo Coach per un record con i due campi seguenti, nell'ordine indicato:

  • name: il nome dell'allenatore, di tipo String.
  • formerPlayer: indica se l'allenatore era un ex giocatore, di tipo Bool.

Definisci l'alias di tipo Stats per un record con i due campi seguenti, nell'ordine indicato:

  • wins: il numero di vittorie, di tipo Int.
  • losses: il numero di sconfitte, di tipo Int.

Definisci l'alias di tipo Team per un record con i tre campi seguenti, nell'ordine indicato:

  • name: il nome della squadra, di tipo String.
  • coach: l'allenatore della squadra, di tipo Coach.
  • stats: le statistiche della squadra, di tipo Stats.

2. Crea una squadra

Vuoi interfacciarti con del codice di terze parti che ha il concetto di squadra, ma che chiama il tuo codice con i parametri in un ordine diverso. Aggiungi una funzione createTeam con la seguente firma String -> Stats -> Coach -> Team.

3. Sostituisci l'allenatore

I proprietari delle squadre NBA sono impazienti, e hai scoperto che i cattivi risultati della squadra portavano spesso alla sostituzione dell'allenatore. Implementa la funzione replaceCoach che prende come parametri il nuovo allenatore e la squadra, e restituisce la squadra con il nuovo allenatore:

let
    coach = { name = "Larry Bird", formerPlayer = True }
    stats = { wins = 58, losses =  24 }
    team = { name = "Indiana Pacers", coach = coach, stats =  stats }
    newCoach = { name = "Isiah Thomas", formerPlayer = True }
in
replaceCoach newCoach team
--> { name = "Indiana Pacers"
--  , coach = { name = "Isiah Thomas", formerPlayer = True }
--  , stats = { wins = 58, losses = 24 } }

4. Controlla se dovresti tifare per una squadra

In futuro hai in programma di ideare un algoritmo complicato per decidere se tifare o no per una squadra, ma per questo primo tentativo hai deciso che dovresti tifare per qualsiasi squadra che ha più vittorie che sconfitte.

Vuoi che questa funzione sia riutilizzabile in altri contesti, quindi usa un record estensibile nella firma del tipo per accettare qualsiasi record che abbia i campi rilevanti. Per mantenere la funzione il più concisa possibile, vuoi usare il pattern matching per ottenere stats dal parametro della funzione. Implementa la funzione rootForTeam che prende una squadra e restituisce True se dovresti tifare per quella squadra, altrimenti restituisce False.

let
    spursCoach = { name = "Gregg Popovich", formerPlayer =  False }
    spursStats = { wins = 56, losses = 26 }
    spursTeam = { name = "San Antonio Spurs", coach = spursCoach, stats = spursStats }
in
rootForTeam spursTeam
--> True
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Elm Exercism

Vuoi iniziare Seguace della moda?

Iscriviti a Exercism per imparare e padroneggiare Elm con 28 concetti110 esercizi e il mentoring di persone reali, tutto gratis.