Haskell: ¿Función para determinar la aridad de las funciones?
-
27-10-2019 - |
Pregunta
¿Es posible escribir una función? arity :: a -> Integer
para determinar la aridad de las funciones arbitrarias, de modo que
> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0
?
Solución
Es fácil con OverlappingInstances
:
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
class Arity f where
arity :: f -> Int
instance Arity x where
arity _ = 0
instance Arity f => Arity ((->) a f) where
arity f = 1 + arity (f undefined)
Actual Encontrado problema. Debe especificar el tipo no polimórfico para las funciones polimórficas:
arity (foldr :: (a -> Int -> Int) -> Int -> [a] -> Int)
No sé cómo resolver esto todavía.
Actual2 Como Sjoerd Visscher comentó a continuación "Debe especificar un tipo no polimórfico, ya que la respuesta depende de qué tipo elija".
Otros consejos
Sí, se puede hacer muy, muy fácilmente:
arity :: (a -> b) -> Int
arity = const 1
Justificación: si es una función, puede aplicarla a exactamente 1 argumento. Tenga en cuenta que la sintaxis de Haskell hace imposible aplicar a 0, 2 o más argumentos como f a b
realmente es (f a) b
, es decir, no f applied to a and b
, pero (f applied to a) applied to b
. El resultado puede, por supuesto, ser otra función que se pueda aplicar nuevamente, y así sucesivamente.
Suena estúpido, pero no es más que la verdad.
Si id
tiene arity 1, no debería id x
¿Tienes arity 0? Pero, por ejemplo, id map
es idéntico a map
, que tendría arity 2 en tu ejemplo.
¿Tiene las siguientes funciones la misma aridad?
f1 = (+)
f2 = (\x y -> x + y)
f3 x y = x + y
Creo que tu noción de "aridad" no está bien definida ...
En Haskell, cada "función" toma exactamente un argumento. Lo que parece una función de "múltiple argumento" es en realidad una función que toma un argumento y devuelve otra función que toma el resto de los argumentos. Entonces, en ese sentido, todas las funciones tienen aridad 1.
No es posible con Haskell estándar. Es posible usar las incoherentinstancias o una extensión similar.
Pero, ¿por qué quieres hacer esto? No puede preguntarle a una función cuántos argumentos espera y luego usar este conocimiento para darle precisamente ese número de argumentos. (A menos que esté utilizando la plantilla Haskell, en cuyo caso, sí, espero que sea posible en el momento de la compilación. ¿Está utilizando la plantilla Haskell?)
¿Cuál es tu problema real que estás tratando de resolver?
Qué tal esto:
arity :: a -> Int
arity (b->c) = 1 + arity (c)
arity _ = 0