mundo multiplicar hola funciones español ejemplos basico haskell sml ml

multiplicar - Módulos(ML) vs(Haskell) Clases de tipo



multiplicar haskell (1)

Para entender lo que dice el artículo, tómese un momento para considerar la clase de tipos Monoid en Haskell. Un monoide es cualquier tipo, T , que tiene una función mappend :: T -> T -> T y un elemento de identidad empty :: T para los que se cumple lo siguiente.

a `mappend` (b `mappend` c) == (a `mappend` b) `mappend` c a `mappend` mempty == mempty `mappend` a == a

Hay muchos tipos de Haskell que se ajustan a esta definición. Un ejemplo que viene a la mente de inmediato son los enteros, para los cuales podemos definir lo siguiente.

instance Monoid Integer where mappend = (+) mempty = 0

Puede confirmar que todos los requisitos se mantienen.

a + (b + c) == (a + b) + c a + 0 == 0 + a == a

De hecho, esas condiciones se mantienen para todos los números por encima de la suma, por lo que también podemos definir lo siguiente.

instance Num a => Monoid a where mappend = (+) mempty = 0

Así que ahora, en GHCi, podemos hacer lo siguiente.

> mappend 3 5 8 > mempty 0

Los lectores particularmente observadores (o aquellos con experiencia en matemática) probablemente ya se habrán dado cuenta de que también podemos definir una instancia Monoid para los números sobre la multiplicación .

instance Num a => Monoid a where mappend = (*) mempty = 1 a * (b * c) == (a * b) * c a * 1 == 1 * a == a

Pero ahora el compilador encuentra un problema. ¿Qué definición de mappend debería usar para los números? ¿ mappend 3 5 igual a 8 o 15 ? No hay forma de que decida. Es por esto que Haskell no permite múltiples instancias de una sola clase de tipos. Sin embargo, el problema sigue en pie. ¿Qué instancia Monoid de Num deberíamos usar? Ambos son perfectamente válidos y tienen sentido para ciertas circunstancias. La solución es no usar ninguno. Si observas Monoid en Hackage, verás que no hay una instancia de Monoid de Num , o Integer , Int , Float o Double . En su lugar, hay instancias Monoid de Sum y Product . Sum y el Product se definen como sigue.

newtype Sum a = Sum { getSum :: a } newtype Product a = Product { getProduct :: a } instance Num a => Monoid (Sum a) where mappend (Sum a) (Sum b) = Sum $ a + b mempty = Sum 0 instance Num a => Monoid (Product a) where mappend (Product a) (Product b) = Product $ a * b mempty = Product 1

Ahora, si desea usar un número como Monoid , debe envolverlo en Sum o Tipo de Product . El tipo de Monoid que utilice determinará qué instancia de Monoid se utiliza. Esta es la esencia de lo que el artículo trataba de describir. No hay ningún sistema integrado en el sistema de clases de tipos de Haskell que le permita elegir entre varias intenciones. En su lugar, tienes que saltar a través de aros envolviéndolos y desenvolviéndolos en tipos de esqueleto. Ahora, si considera o no que esto es un problema, es una gran parte de lo que determina si prefiere Haskell o ML.

ML soluciona esto permitiendo que se definan múltiples "instancias" de la misma clase y tipo en diferentes módulos. Luego, el módulo que importe determinará qué "instancia" usará. (Estrictamente hablando, ML no tiene clases e instancias, pero sí tiene firmas y estructuras, que pueden actuar casi igual. Para una comparación más profunda, lea este documento ).

Según Harper ( https://existentialtype.wordpress.com/2011/04/16/modules-matter-most/ ), parece que las Clases de Tipo simplemente no ofrecen el mismo nivel de abstracción que ofrecen los Módulos y estoy teniendo un momento difícil averiguar exactamente por qué. Y no hay ejemplos en ese enlace, así que es difícil para mí ver las diferencias clave. También hay otros artículos sobre cómo traducir entre módulos y clases de tipo ( http://www.cse.unsw.edu.au/~chak/papers/modules-classes.pdf ), pero esto realmente no tiene nada que ver con ver con la implementación en la perspectiva del programador (solo dice que no hay algo que uno pueda hacer que el otro no pueda emular).

En concreto, en el https://existentialtype.wordpress.com/2011/04/16/modules-matter-most/ :

La primera es que insisten en que un tipo puede implementar una clase de tipo exactamente de una manera. Por ejemplo, de acuerdo con la filosofía de las clases de tipos, los enteros se pueden ordenar de una manera precisa (el ordenamiento habitual), pero obviamente hay muchos ordenamientos de interés (por ejemplo, por divisibilidad). La segunda es que confunden dos cuestiones separadas: especificar cómo un tipo implementa una clase de tipo y especificar cuándo se debe usar dicha especificación durante la inferencia de tipo.

Yo tampoco entiendo ¿Un tipo puede implementar una clase de tipos en más de 1 forma en ML? ¿Cómo tendría los enteros ordenados por divisibilidad por ejemplo sin crear un nuevo tipo? En Haskell, tendría que hacer algo como usar datos y tener la instance Ord para ofrecer un pedido alternativo.

Y el segundo, ¿no son los dos distintos en Haskell? Especificar "cuándo se debe usar una especificación de este tipo durante la inferencia de tipo" se puede hacer mediante algo como esto:

blah :: BlahType b => ...

donde BlahType es la clase que se utiliza durante la inferencia de tipo y NO la clase de implementación. Mientras que, "cómo un tipo implementa una clase de tipo" se hace usando la instance .

¿Alguien puede explicar lo que realmente intenta decir el enlace? Simplemente no entiendo por qué los módulos serían menos restrictivos que las clases de tipo.