Haskell vergleicht ein Generikum mit einem Char
Ich muss eine Haskell-Funktion erstellen, die eine generische Eingabe hat, aber einen Booleschen Wert ausgibt, je nachdem, ob die generische Funktion mit bestimmten Ziffern / Zeichen übereinstimmt.
checkFunct :: a -> Bool
checkFunct x = (elem x ['a','b','c'])
Wie das nicht funktioniert, weil man Char nicht mit Generika vergleichen kann. Ich habe lange gesucht und bin neu in Haskell, habe also keine Ahnung, wie ich das beheben soll. Hinweis: Es wurde ausdrücklich angegeben, dass die Eingabe ein -> Bool sein muss
Zum Beispiel funktioniert dieser Code perfekt:
checkFunct :: Char -> String
p x = elem x ["a","b","c"]
Allerdings brauche ich 'a' von Char. Entschuldigen Sie die Verwirrung. (Anscheinend ist 'a' kein Generikum)
Antworten
Eine mögliche Interpretation der Frage lautet: Sie möchten, dass die Funktion erkennt, ob das Argument a Charund in der Liste ist . Sie können dies nicht nur mit der Signatur tun a -> Bool, da für Funktionen keine Typinformationen verfügbar sind. Sie können jedoch explizit Typinformationen anfordern: Hierfür gibt es eine dedizierte Klasse .
import Data.Typeable
checkFunct :: Typeable a => a -> Bool
checkFunct x = case cast x of
Just xc -> xc `elem` ['a','b','c']
Nothing -> False
(Beachten Sie, dass im Gegensatz zu vielen anderen Sprachen Typencast nicht wirklich konvertiert werden , sondern nur übereinstimmt, ob es sich überhaupt um den Zieltyp handelt.)
*Main> checkFunct 'b'
True
*Main> checkFunct 'f'
False
*Main> checkFunct 37
False
*Main> checkFunct "a"
False
Eine Funktion vom Typ a -> Bool, für die kurz steht forall a. a -> Bool, ist für sich genommen nicht sehr nützlich, da sie "für alle a" funktionieren muss , die der Aufrufer angibt, sodass sie nichts darüber wissen darf a. Aus diesem Grund erhalten Sie Antworten mit der Aufschrift „Sie können von hier aus nicht dorthin gelangen“.
(Tatsächlich gibt es bei diesem Typ nur zwei reine Gesamtfunktionen: alwaysTrue _ = Trueund alwaysFalse _ = False.)
Aber ich vermute, basierend auf Ihrem Kommentar:
Ich benötige eine Funktion mit und Eingabe von
:: a -> Boolund sie muss berechnen, obaes sich um ein Element in einer bestimmten Liste handelt.
Dass Ihre Frage im Zusammenhang mit einer Funktion wie dieser steht:
contains :: (a -> Bool) -> [a] -> Bool
Jetzt können wir etwas Nützliches tun! Sehen Sie, dieser Typ ist die Abkürzung für forall a. (a -> Bool) -> [a] -> Bool, das heißt, er arbeitet auch mit Werten eines beliebigen Typs a, aber auch hier ist der Aufrufer dieser Funktion derjenige, der adas Prädikat des Typs a -> Bool für einen bestimmtena sowie auswählt und übergibt eine Liste von aWerten. Weiß containsalso nichts darüber a, aber es weiß , dass es das Prädikat auf die Elemente der Liste anwenden kann, da sie garantiert vom gleichen Typ sind.
So zum Beispiel können Sie diese Funktion mit einem Argument vom Typ nennen Char -> Bool, die Sätze azu Char, oder eines der Typen Int -> Bool, die Sätze azu Int, und so weiter:
isABC :: Char -> Bool
isABC x = x `elem` "abc"
-- contains :: (a -> Bool) -> [a] -> Bool
-- contains isABC :: [Char] -> Bool
-- contains isABC "yeah" == True
-- contains isABC "nope" == False
is123 :: Int -> Bool
is123 x = x >= 1 && x <= 3
-- contains is123 :: [Int] -> Bool
-- contains is123 [] == False
-- contains is123 [0] == False
-- contains is123 [0, 1] == True
Wenn Sie diese Funktion selbst schreiben möchten contains, können Sie eine rekursive Definition mit dieser allgemeinen Struktur verwenden:
contains :: (a -> Bool) -> [a] -> Bool
contains predicate list = case list of
-- How can you test the current element with the predicate?
-- What should you do when the predicate returns true?
-- How can you test the rest of the list?
current : rest -> _
-- What should you return if you’ve reached the end?
[] -> _
Die Unterstriche werden als typisierte Löcher bezeichnet , die Sie in Ihr Programm aufnehmen können, um GHC zu bitten, Ihnen mitzuteilen, welchen Typ es dort erwartet, und Ihnen einige Vorschläge für Funktionen und Variablen im Umfang zu geben, die möglicherweise passen. Wenn Sie herausfinden, wie Sie weitere Details Ihres Programms ausfüllen können, können Sie mehr Löcher verwenden, um nach den Typen spezifischerer Teile zu fragen, z. B. können Sie das erste Loch durch ersetzen if _ then _ else _.
Hier kann die TypeApplicationsErweiterung hilfreich sein (aktiviert in GHCi mit :set -XTypeApplicationsoder in einer Quelldatei mit {-# LANGUAGE TypeApplications #-}), mit der Sie die Typargumente explizit ausschreiben können, z. B. in GHCi:
> :set -XTypeApplications
> contains :: (a -> Bool) -> [a] -> Bool; contains = error "TODO: implement 'contains'"
> :type contains @Char
contains @Char :: (Char -> Bool) -> [Char] -> Bool
> :type contains @Int
contains @Int :: (Int -> Bool) -> [Int] -> Bool
> :t map
map :: (a -> b) -> [a] -> [b]
> :t map @Double
map @Double :: (Double -> b) -> [Double] -> [b]
> :t map @Double @Int
map @Double @Int :: (Double -> Int) -> [Double] -> [Int]
Und was machst du gerne, wenn aes so etwas ist b -> FreeT (PipeF a b)?
Ihr Typ sagt, ich kann Ihnen alles geben, was Sie können , und Sie werden feststellen, Booldass es nur zwei Möglichkeiten gibt, diese Funktion zu schreiben. checkFunct _ = TrueundcheckFunct _ = False
Sie müssen dem Compiler etwas mehr darüber erzählen, was Sie als Eingabe erwarten.
Aus Ihrer Beispielimplementierung geht hervor, dass Sie möglicherweise sehen möchten, ob sich die Zeichenfolgendarstellung von x in einer Liste befindet.
Sie könnten schreiben:
checkFunct :: Show a => a -> Bool
checkFunct x = (elem (show x) ["a","b","c"])
Das Show a =>sagt, dass alles, was ich als Eingabe für diese Funktion gebe, show aeine Zeichenfolge zurückgeben muss.
Oder vielleicht möchten Sie Ihre eigene Klasse schreiben
class ToChar a where
toChar :: a -> Char
Sie könnten dann schreiben:
checkFunct :: ToChar a=> a -> Bool
checkFunct x = (elem (toChar x) ['a','b','c'])
Um 'checkFunct' verwenden zu können, müssten Sie eine Implementierung von toChar für jeden Typ bereitstellen, den Sie mit dieser Funktion verwenden möchten.
import Data.Char
instance ToChar Int where
toChar = chr