Haskell, comparando un genérico con un Char
Necesito hacer una función de Haskell que tenga una entrada genérica pero genere un booleano dependiendo de si el genérico coincide con ciertos dígitos / caracteres, algo como:
checkFunct :: a -> Bool
checkFunct x = (elem x ['a','b','c'])
Cómo esto no funcionará porque no puedes comparar Char con genérico. He buscado durante años y soy nuevo en Haskell, así que no tengo idea de cómo solucionarlo. Nota: si se indica específicamente que la entrada debe ser un -> Bool
Por ejemplo, este código funciona perfectamente:
checkFunct :: Char -> String
p x = elem x ["a","b","c"]
Sin embargo, necesito 'a' en lugar de Char. Perdón por cualquier confusión. (Aparentemente 'a' no es genérico)
Respuestas
Una posible interpretación de la pregunta es: desea que la función diga si el argumento es ay Charen la lista . No puede hacer eso solo con la firma a -> Bool, porque la información de tipo no está disponible para las funciones, sin embargo, puede requerir información de tipo explícitamente: hay una clase dedicada para esto .
import Data.Typeable
checkFunct :: Typeable a => a -> Bool
checkFunct x = case cast x of
Just xc -> xc `elem` ['a','b','c']
Nothing -> False
(Tenga en cuenta que, a diferencia de muchos otros idiomas, en castrealidad no convierte tipos , solo coincide con si era el tipo de destino en primer lugar).
*Main> checkFunct 'b'
True
*Main> checkFunct 'f'
False
*Main> checkFunct 37
False
*Main> checkFunct "a"
False
Por sí sola, una función de tipo a -> Bool, que es la abreviatura de forall a. a -> Bool, no sirve de mucho, ya que debe funcionar “para todos a” que especifique el llamador, por lo que no se le permite saber nada a. Es por eso que está recibiendo respuestas que básicamente dicen "no se puede llegar desde aquí".
(De hecho, solo hay dos funciones totales puras con este tipo: alwaysTrue _ = Truey alwaysFalse _ = False).
Pero supongo, basándome en este comentario tuyo:
Necesito una función que tenga una entrada de
:: a -> Booly necesita calcular siaes un elemento en una lista específica.
Que tu pregunta está en el contexto de una función como esta:
contains :: (a -> Bool) -> [a] -> Bool
¡Ahora podemos hacer algo útil! Mira, este tipo es la abreviatura de forall a. (a -> Bool) -> [a] -> Bool, es decir, también opera sobre valores de cualquier tipo a, pero nuevamente, el llamador de esta función es quien elige ay pasa el predicado de tipo a -> Bool para algunos específicosa , así como una lista de avalores. Entonces containsno sabe nada a, pero sí sabe que puede aplicar el predicado a los elementos de la lista, ya que se garantiza que son del mismo tipo.
Entonces, por ejemplo, puede llamar a esta función con un argumento de tipo Char -> Bool, que establece aen Char, o uno de tipo Int -> Bool, que establece aen Int, y así sucesivamente:
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
Si desea escribir esta containsfunción usted mismo, puede usar una definición recursiva, con esta estructura general:
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?
[] -> _
Los guiones bajos se denominan agujeros escritos , que puede incluir en su programa para pedirle a GHC que le diga qué tipo está esperando allí y darle algunas sugerencias de funciones y variables en el alcance que podrían encajar. A medida que descubra cómo completar más detalles de su programa, puede usar más agujeros para solicitar los tipos de piezas más específicas, por ejemplo, puede reemplazar el primer agujero con if _ then _ else _.
Algo que puede ser útil aquí es la TypeApplicationsextensión (habilitada en GHCi con :set -XTypeApplicationso en un archivo fuente con {-# LANGUAGE TypeApplications #-}), que le permite escribir los argumentos de tipo explícitamente, por ejemplo, en 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]
¿Y qué te gustaría hacer si aes algo así b -> FreeT (PipeF a b)?
Su tipo dice que puedo entregarle la función cualquier cosa y se le ocurrirá Boolque solo hay dos formas de escribir esta función. checkFunct _ = TrueycheckFunct _ = False
Necesita decirle al compilador un poco más sobre lo que espera como entrada.
A partir de su implementación de ejemplo, supongo que es posible que desee ver si la representación de cadena de x está en una lista.
Podrías escribir:
checkFunct :: Show a => a -> Bool
checkFunct x = (elem (show x) ["a","b","c"])
el Show a =>dice que todo lo que os doy como entrada a esta función, show adebe devolver una cadena.
O quizás quieras escribir tu propia clase
class ToChar a where
toChar :: a -> Char
Entonces podrías escribir:
checkFunct :: ToChar a=> a -> Bool
checkFunct x = (elem (toChar x) ['a','b','c'])
Para usar 'checkFunct', necesitaría proporcionar una implementación de toChar para cualquier tipo que quisiera usar con esa función.
import Data.Char
instance ToChar Int where
toChar = chr