2016-04-07 8 views
1

Ich habe endlich einen exzellenten Einstiegspunkt in die funktionale Programmierung mit Ulme gefunden, und, Junge, mag ich es, aber mir fehlt noch eine gewisse grundsätzliche Eleganz in Bezug auf einige Konzepte.Map List auf shifted self

Ich finde oft, dass ich Code schreibe, der dem folgenden ähnlich ist, der zu tun scheint, was er sollte, aber wenn jemand Erfahrener einen kompakteren und direkteren Ansatz vorschlagen könnte, bin ich sicher, dass er wertvolle Einsichten in dieses Thema geben könnte so (U) Rarität.

Was ich mir vorstellen, diese kochen könnte nach unten, ist so etwas wie die folgenden (<-> ist ein Vektor Subtraktionsoperator):

edgeDirections : List Vector -> List Vector 
edgeDirections corners = List.map2 (\p v -> p <-> v) corners (shiftr 1 corners) 

aber ich habe nicht wirklich eine befriedigende Annäherung an ein Verfahren, das würde Tun Sie eine shiftr.

Aber die Regeln von stackoverflow verlangen es, hier ist, was ich versucht habe. Ich schrieb ein hässliches Beispiel für eine mögliche Nutzung für shiftr (Ich mag nicht unbedingt die Debug.crash und ich bin nicht glücklich über die Maybe):

In einer vorgegebenen Liste von Vektoren (die Eckpunkte eines Polygons), berechnen die Richtungsvektoren durch Berechnen der Differenz jedes Eckvektors zu seinem vorherigen, beginnend mit dem Unterschied zwischen dem ersten und dem letzten Eintrag in der Liste.

[v1,v2,v3] -> [v1-v3,v2-v1,v3-v2]

Hier geht:

edgeDir : Vector -> (Maybe Vector, List Vector) -> (Maybe Vector, List Vector) 
edgeDir p (v, list) = 
    case v of 
    Nothing -> 
     Debug.crash ("nono") 

    Just vector -> 
     (Just p, list ++ [ p <-> vector ]) 


edgeDirections : List Vector -> List Vector 
edgeDirections corners = 
    let 
    last = 
     List.head <| List.reverse corners 
    in 
    snd <| List.foldl edgeDir (last, []) corners 


main = 
    show <| edgeDirections [ Vector -1 0, Vector 0 1, Vector 1 0 ] 

Ich schätze jeden Einblick, wie dieses Ergebnis in einer direkteren Art und Weise erreicht werden könnte, vielleicht vorhandene Sprachkonstrukte mit mir jetzt noch nicht bewusst bin, oder jede Hinweise, wie man den Schmerz mit Maybe lindern kann. Letzteres kann nicht möglich sein, aber ich bin mir sicher, dass die ehemalige a) mich wegblasen und b) mich meinen Kopf ein paar Mal kratzen lassen wird.

Vielen Dank und vielen Dank für diese gelungene Sprache!

Antwort

2

Wenn Elm init and last Funktionen eingebaut hatte, könnte dies sauberer sein.

Sie können von all diesen Maybes wegkommen, indem Sie einen Mustervergleich durchführen. Hier ist mein Versuch, nur Mustererkennung und einen Akku zu verwenden.

import List exposing (map2, append, reverse) 

shiftr list = 
    let shiftr' acc rest = 
    case rest of 
     [] -> [] 
     [x] -> x :: reverse acc 
     (x::xs) -> shiftr' (x::acc) xs 
    in shiftr' [] list 

edgeDirections vectors = 
    map2 (<->) vectors <| shiftr vectors 

Beachten Sie auch die verkürzte Schreiben der Abbildungsfunktion von (<->), die (\p v -> p <-> v) entspricht.

Angenommen Elm hat haben eine init und last Funktion - definieren wir nur diejenigen, schnell hier:

init list = 
    case list of 
    [] -> Nothing 
    [_] -> Just [] 
    (x::xs) -> Maybe.map ((::) x) <| init xs 

last list = 
    case list of 
    [] -> Nothing 
    [x] -> Just x 
    (_::xs) -> last xs 

Dann Ihre shiftr Funktion etwas verkürzt werden könnte wie:

shiftr list = 
    case (init list, last list) of 
    (Just i, Just l) -> l :: i 
    _ -> list 
+0

Das ist genau das Muster, das ich vorher gesehen hatte und dachte, dass es hier anwendbar sein könnte. Danke für die Demonstration! Nur aus Neugier, impliziert '(x :: xs)', dass 'x' nicht' Nichts' ist? Edit: Streik, ich bin sicher, dass es nicht bedeutet, dass, deshalb ist das vorteilhaft, verstanden. – mindandmedia

0

Kurz nachdem ich „aufgehängt“, kam ich mit diesem, aber ich bin sicher, dass dies immer noch stark verbessert werden kann, wenn es auch richtig ist (und es funktioniert nur für n = 1)

shiftr : List a -> List a 
shiftr list = 
    let 
    rev = 
     List.reverse list 
    in 
    case List.head rev of 
     Nothing -> 
     list 

     Just t -> 
     [ t ] ++ (List.reverse <| List.drop 1 rev) 


main = 
    show (shiftr [ 1, 2, 3, 4 ] |> shiftr)