[Haskell] Warum ist soetwas nicht möglich?



  • foo :: [Integer] -> Integer -> Integer -> [Integer]
    foo list index value = list
        where
        list!!index = value
    

    Syntaktisch ok, aber ich möchte natürlich oben die veränderte Liste ala:

    foo :: [Integer] -> Integer -> Integer -> [Integer]
    foo list index value = newList
        where
        newList = list with list!!index = value
    

    Warum ist das nicht möglich? Bzw. wie ist es möglich?

    MrN hat mir einen Weg gezeigt die Liste in einen Teil A davor, den neuen value und einen Teil B danach zu splitten:

    (pre, value:post) = splitAt index list
    newList = pre ++ [value] ++ post
    

    Der ist aber insofern übel weil es sein kann, dass es kein post gibt und hier dann zusätzlihc noch eine Fallunterscheidung dazukommt...

    Kennt niemand etwas "schönes"? Ist das aus irgendeinem bestimmten Grund nicht möglich?

    MfG SideWinder



  • Ich bin zwar selbst noch Anfänger, aber ich kann ja trotzdem versuchen auf die Fragen zu antworten.

    Warum ist das nicht möglich?

    Ich denke, dass das nicht möglich ist, weil Listen (wie alles andere in Haskell) unveränderlich sind.

    Der ist aber insofern übel weil es sein kann, dass es kein post gibt und hier dann zusätzlihc noch eine Fallunterscheidung dazukommt...

    Vielleicht so in etwa:

    assign :: [Int] -> Int -> Int -> [Int]
    assign list i v = 
       let (pre, post) = splitAt i list
       in case post of
           [] -> init pre ++ [v]
           (x : post') -> pre ++ [v] ++ post'
    

    Aber darauf wärst du warhscheinlich auch gekommen. Bei komplett leeren Listen dürfte es zusätzlich noch crashen (init []).

    Vielleicht können die Haskell Spezis bessere Vorschläge machen. Würde mich auch interessieren.



  • Frag mal dei mongolischen Nomaden, kurz Monaden.



  • Unveränderlich, das stimmt. Er könnte ja die gesamte Liste kopieren und eine neue Liste erstellen mit dem geänderten Wert. Das wäre immer noch wesentlich performanter als die gezeigte assign-Lösung.

    MfG SideWinder



  • Annahme: Ich muss >n/2 Werte setzen in der Liste - die Werte erhalte ich über (index,value)-Tupel.

    Ist es schöner diese Input-Liste nach index zu sortieren und dann soetwas zu schreiben:

    foo :: [(Integer,Integer)] -> Integer -> Integer -> [Integer]
    foo inp def max = foo' inp def 0 max
    
    foo' :: [(Integer,Integer)] -> Integer -> Integer -> Integer -> [Integer]
    foo' inp def cur max
        | cur == max = [cell]
        | otherwise = (cell:cells)
        where
        cell = getCell inp def cur
        cells = foo' inp def (cur+1) max
    
    cell :: [(Integer,Integer)] -> Integer -> Integer -> Integer
    cell [] def _ = def
    cell ((i,v):xs) cur def
        | cur == i = v
         | otherwise = def
    

    Das sieht ja vielleicht einmal ekelig aus. Wenn das die Eleganz von funktionalen Sprachen sein soll, dann gute Nacht. Aber zum Glück bin ich ja hier Anfänger und man zeigt mir gleich auf wie die Eleganz von funktionalen Sprachen aussieht 🙂

    MfG SideWinder



  • Wenn du deine Frage nicht im Code verstecken wuerdest und sie normal in Worte formulierst, waere allen geholfen.

    list!!index = value
    

    Du willst eine Zuweisung. Haskell trennt funktionalen Teil (keine Zuweisung) von zustandsbehafteten Programmcode durch das Typsystem (IO m). Was du vorhast, wird in Haskell schlichtweg anders geloest.

    Da du aber nicht sagst, in welchem Kontext oder Problem du es benoetigst, kann ich dir keine schoene Alternative anbieten.



  • Ich muss aus einer Adjazenzliste eine Adjazenzmatrix machen, wobei bei mir Matrix nur eine Liste von gleichlangen Listen ist. Jetzt wollte ich zuerst eine genügend große Matrix erstellen und dann die Kosten in die Matrix eintragen, genau an der Stelle die in der Adjazenzliste angegeben ist.

    Nun ist meine Lösung, dass ich die Adjazenzliste sortiere und die Adjazenzmatrix quasi Eintrag für Eintrag aufbaue und jedesmal die Liste prüfe ob da ein Wert hin muss.

    MfG SideWinder



  • Ich nehme mal das Beispiel aus: http://www.tilman.de/uni/ws03/alp/adjazenz.php .

    Die Liste ist gegeben mit:

    ls = [ [2,3], [], [1,4,6], [1], [3,5], [2,4,5] ]
    

    wir wollen erstmal z.B. aus [2,3] sowas wie [0,1,1,0,0,0] machen:

    f [] a = repeat 0
    f (x:xs) a | x == a = 1 : f (xs) (a+1)
               | otherwise = 0 : f (x:xs) (a+1)
    

    Es wird noch explizit Rekursion verwendet, vielleicht kann man da was besseres mit Bibliotheksfunktionen basteln. Insgesamt soll unser Graph 6 Knoten haben, wobei die Numerierung bei 1 anfaengt:

    ms = map (\x -> take 6 $ f x 1) ls
    

    Da es sich um eine Matrix/Array handelt, koennen die Listen am besten noch in ein Array ueberfuehrt werden, damit die Zugriffszeit passabel ist.

    Wenn du Kosten(funktion) zusaetzlich haben moechtest, dann musst du mir ein geeignetes Beispiel geben.


Anmelden zum Antworten