Ich lerne funktionale Programmierung mit Haskell und ich habe diese Übung, in der ich so etwas wie [a], z habe, mit [a] jeder Art von Liste und z dem Element, das ich in [a] löschen werde . Dieses Problem ist leicht zu lösen (selbst für einen Neuling wie mich in Haskell), aber ich habe Probleme mit der Art und Weise, wie ich die Ausgabe drucken muss.

Ich muss ein Tupel erstellen, bei dem das erste Element die Liste ohne z Element ist und wie oft z in a gefunden wurde. Paar Beispiele:

  • Eingabe: [2,3,4,2,2] 2
  • Ausgabe: ([3,4],3)

  • Eingabe: [1,1,1,1] 1

  • Ausgabe: ([],4)

  • Eingabe: [1,2,3,4] 5

  • Ausgabe: ([1,2,3,4],0)

Bisher habe ich so etwas gemacht, aber ich weiß nicht, wie ich weitermachen soll:

ex3 :: (Eq a, Num a) => [a] -> a -> ([a],Int)
ex3 [] _ = ([],0)
ex3 (x:xs) z | x == z = (xs,1) -- this line is wrong, but idk how to fix it
             | otherwise = ([0],0) -- same here

Ich habe beide Probleme einzeln gelöst (z Elemente löschen und zählen, wie oft z in [a] enthalten ist. Sieht folgendermaßen aus:

A) Löschen von z Elementen:

ex3a :: (Eq a) => [a] -> a -> [a]
ex3a [] _ = []
ex3a (x:xs) z | x == z = ex3a xs z
              | otherwise = x : ex3a xs z

B) Zählen, wie oft z in [a] ist:

ex3b :: (Eq a) => [a] -> a -> Int
ex3b [] _ = 0
ex3b (x:xs) z | x == z = 1 + ex3b xs z
              | otherwise = ex3b xs z
2
Frank Ponte 19 Apr. 2018 im 20:08

3 Antworten

Beste Antwort

Normalerweise hilft es, an Funktionen wie in der Mathematik zu denken, die Sie an induktive Definitionen denken. Zum Beispiel kann die erste Zeile Ihrer Funktion wie folgt lauten:

" Das ex3 einer leeren Liste, und jedes Element ist ein Tupel, das die leere Liste und Null enthält."

ex3 [] _ = ([], 0)

Bei nicht leeren Listen ist das Problem natürlich etwas schwieriger. Wie in Ihrem Code gibt es hier grundsätzlich zwei Fälle.

" Das ex3 einer nicht leeren Liste und eines Elements z, bei dem der Kopf der Liste ungleich z ist, ist dasselbe wie das ex3 des Endes der Liste , aber vor dem Kopf dieser Liste ", damit wir es wie folgt schreiben können:

ex3 [] _ = ([], 0)
ex3 (x:xs) z | x /= z = (x:t, n)
             | otherwise = ...
    where (t, n) = ex3 xs z

Hier rufen wir also ex3 mit dem Ende der Liste xs rekursiv auf und erhalten das Ergebnistupel (t, n), sodass t das "gelöschte" Ende enthält. und n wie oft wir das Element entfernt haben, und im Fall von x /= z können wir (x:t, n) zurückgeben, da sich die Anzahl der Entfernungen nicht ändert, wir aber {{voranstellen müssen X7}} zur Liste.

" Das ex3 einer nicht leeren Liste und eines Elements z, bei dem der Kopf der Liste gleich z ist, entspricht dem ex3 der Ende der Liste, jedoch mit einer erhöhten Anzahl ", also:

ex3 :: (Eq a, Num n) => [a] -> a -> ([a], n)
ex3 [] _ = ([], 0)
ex3 (x:xs) z | x /= z = (x:t, n)
             | otherwise = (t, n+1)
    where (t, n) = ex3 xs z

Wir erhalten dann die erwarteten Ergebnisse:

Prelude> ex3 [2,3,4,2,2] 2
([3,4],3)
Prelude> ex3 [1,1,1,1] 1
([],4)
Prelude> ex3 [1,2,3,4] 5
([1,2,3,4],0)
5
melpomene 19 Apr. 2018 im 17:36

Nur zum Spaß würde ich diese Funktion folgendermaßen implementieren:

import Data.Foldable
import Data.Monoid

ex3 :: Eq a => [a] -> a -> ([a], Int)
ex3 haystack needle = getSum <$> foldMap inject haystack where
    inject hay | hay == needle = ([], 1)
               | otherwise     = ([hay], 0)

Was mir daran gefällt, ist, dass das Rekursionsmuster - zumindest für diejenigen, die mit Haskells Standardbibliothek vertraut sind - ohne sorgfältige Prüfung sofort offensichtlich ist (da es sich nur um einen Aufruf von foldMap handelt).

3
Daniel Wagner 19 Apr. 2018 im 17:43

Die Partitionsfunktion verwendet ein Prädikat und eine Liste. Es werden zwei Listen erstellt, deren erstes Element das Prädikat erfüllt, das zweite nicht.

import Data.List (partition)

ex4 :: Eq a => [a] -> a -> ([a], Int)
ex4 xs x = length <$> partition (/= x) xs
0
user12457 20 Apr. 2018 im 05:46