una tres suma rotacion potencia palindromo numeros multiplos mayor listas lista elemento ejercicios codigo haskell functional-programming type-inference typeclass

tres - ¿Por qué suma xy es de tipo(Num a)=> a-> a-> a en Haskell?



rotacion de listas en haskell (5)

Esto es porque

Cada función en Haskell toma un solo parámetro y devuelve un valor único

Si una función necesita tomar valores múltiples, la función habría sido una función curried o tiene que tomar una sola tupla .

Si agregamos un paréntesis, la firma de la función se convierte en:

sum :: (Num a) => a -> (a -> a)

En Haskell, la firma de la función: A -> B significa una función, el "dominio" de la función es A y el "Codominio" de la función es B ; o en el lenguaje de un programador, la función toma un parámetro de tipo A y devuelve un valor de tipo B

Por lo tanto, la definición de función sum :: Num -> (Num -> Num) significa que sum es "una función que toma un parámetro de tipo a y devuelve una función de tipo Num -> Num ".

En efecto, esto conduce a currying / función parcial.

El concepto de currying es esencial en lenguajes funcionales como Haskell, porque querrás hacer cosas como:

map (sum 5) [1, 2, 3, 5, 3, 1, 3, 4] -- note: it is usually better to use (+ 5)

En ese código, (suma 5) es una función que toma un solo parámetro, se llamará a esta función (suma 5) para cada elemento de la lista, por ejemplo, ((suma 5) 1) devuelve 6.

Si sum tuviera una firma de sum :: (Num, Num) -> Num , entonces sum tendría que recibir ambos parámetros al mismo tiempo porque now sum es una "función que recibe una tuple (Num, Num) y devuelve un Num ".

Ahora, la segunda pregunta, ¿qué significa Num a => a -> a ? Básicamente es una forma abreviada de decir que cada vez que veas a en la firma, reemplázalo con Num o con una de sus clases derivadas.

He estado leyendo sobre Haskell y me cuesta entender cómo se manejan las definiciones de funciones en este lenguaje.

Digamos que estoy definiendo una función de sum :

let sum x y = x + y

si consulto a Haskell por su tipo

:t sum

yo obtengo

sum :: (Num a) => a -> a -> a

  1. ¿Qué significa el operador => ? ¿Tiene algo que ver con las expresiones lambda? Así es como se señala que lo que sigue al operador => es uno, en C #.
  2. ¿Qué significa a -> a -> a ? A través de la inspección ocular en una serie de funciones diferentes que he estado probando, parece que la inicial a -> a son los argumentos y la final -> a es el resultado de la función suma. Si eso es correcto, ¿por qué no algo como (a, a) -> a , que parece mucho más intuitivo?


es a -> a -> a lugar de (a, a) -> a debido al currying . Dato curioso: ¡Curry fue (re) inventado por Haskell Curry! Básicamente significa que si proporciona un argumento uno obtendrá otra función de tipo a -> a , una aplicación parcial de suma.


Num a => significa "en lo siguiente, a se referirá a un tipo que es una instancia de la clase de clase Num " (que es como una interfaz para tipos de números).

El operador => separa las "restricciones de clase de tipo" del "cuerpo" del tipo. Es algo así como el operador where para restricciones genéricas en C #. Puedes leerlo como una implicación lógica como "si a es un tipo numérico, entonces la sum se puede usar con el tipo a -> a -> a ".

a -> a -> a significa "una función que toma una a y devuelve una función que toma una a y devuelve una a ". Para que tenga sentido, debe comprender que sum xy analiza como (sum x) y .

En otras palabras: primero se llama sum con el argumento x . A continuación, recupera una nueva función de tipo a -> a . Luego llama a esa función con el argumento y y ahora recupera una función de tipo a , donde a es el tipo de y y debe ser una instancia de la clase de tipo Num .

Si desea que sum tenga el tipo Num a => (a,a) -> a , puede definirlo como sum (x,y) = x+y . En este caso, tiene una función que toma una tupla que contiene dos a sy devuelve una a (donde a es nuevamente una instancia de la clase de tipo Num ).

Sin embargo, el "estilo de curry" (funciones que devuelven funciones para simular múltiples parámetros) se usa mucho más a menudo que el estilo de tupla, ya que le permite aplicar funciones de manera sencilla. map (sum 5) [1,2,3] ejemplo map (sum 5) [1,2,3] . Si hubiera definido la sum con una tupla, tendría que hacer un map (/y -> sum 5 y) [1,2,3] .


0. El Haskell => no tiene nada que ver con C # ''s => . En Haskell se crea una función anónima con

/x -> x * x

Además, no asigne un nombre a la sum la función porque dicha función ya existe en Preludio. Vamos a llamarlo plus partir de ahora para evitar confusiones.

1. De todos modos, el => en Haskell proporciona un contexto para el tipo. Por ejemplo:

show :: (Show a) => a -> String

Aquí, The Show a => significa que a tipo debe ser una instancia de la clase de tipo Show , lo que significa que debe ser convertible a una cadena. De manera similar, (Num a) => a -> a -> a significa que el tipo a debe ser una instancia del tipo clase Num, lo que significa que debe ser como un número. Esto pone una restricción en a para que show o plus no acepten alguna entrada no admitida, por ejemplo, plus "56" "abc" . (La cadena no es como un número).

Una clase de tipo es similar a la interfaz de C #, o más específicamente, una restricción de tipo base de interfaz en genéricos . Vea la pregunta Explain Type Classes en Haskell para más información.

2. a -> a -> a significa a -> (a -> a) . Por lo tanto, en realidad es una función unaria que devuelve otra función.

plus x = /y -> x + y

Esto hace que la aplicación parcial (currying) sea muy fácil. La aplicación parcial se usa mucho especialmente cuando se usan funciones de orden superior. Por ejemplo, podríamos usar

map (plus 4) [1,2,3,4]

para agregar 4 a cada elemento de la lista. De hecho, podríamos volver a utilizar una aplicación parcial para definir:

plusFourToList :: Num a => [a] -> [a] plusFourToList = map (plus 4)

Si una función está escrita en la forma (a,b,c,...)->z de forma predeterminada, tendríamos que introducir muchas lambdas:

plusFourToList = /l -> map(/y -> plus(4,y), l)