programacion preguntas paradigmas orientada objetos logica funcional caracteristicas haskell clojure protocols typeclass multimethod

preguntas - ¿Cuáles son las razones por las cuales los protocolos y los métodos multimétodos en Clojure son menos potentes para el polimorfismo que las clases de tipos en Haskell?



programacion funcional vs orientada a objetos (2)

Bueno, el más obvio es que los protocolos solo pueden enviarse en el primer y solo el primer argumento. Esto significa que son aproximadamente equivalentes a

class Foo a where bar :: a -> ... quux :: a -> ... ...

Donde debe ser el primer argumento. Las clases de tipos de Haskell permiten que aparezca en cualquier parte de la función. Entonces los protocolos son fácilmente menos expresivos que las clases de tipos.

El siguiente es multimétodos. Los métodos multimétodos, si no me equivoco, permiten el despacho basado en una función de todos los argumentos. Esto se ve más expresivo en algunos aspectos que Haskell, ya que puede enviar argumentos del mismo tipo de forma diferente. Sin embargo, esto realmente se puede hacer en Haskell, generalmente envolviendo el argumento en un nuevo tipo para despachar.

Algunas cosas que no se pueden hacer con multimedios según mi conocimiento:

  1. Despacho en el tipo de devolución
  2. Almacenar valores polimórficos sobre todos los tipos de una clase de tipo para todo forall a. Foo a => a forall a. Foo a => a

Para ver cómo 1. entra en juego, considere Monoid tiene un valor mempty :: Monoid m => m . No es una función, y simular esto es imposible con Clojure ya que no tenemos ningún tipo de información sobre qué método debemos elegir.

Para 2. considere read :: Read a => String -> a . En Haskell podríamos crear una lista que tenga el tipo [forall a. Read a => a] [forall a. Read a => a] , esencialmente hemos diferido el cálculo y ahora podemos ejecutar y volver a ejecutar los elementos de la lista para intentar leerlos como valores diferentes.

Las clases de tipos también tienen tipos estáticos, por lo que hay algunas comprobaciones para asegurarse de que no van a quedar "bloqueados" sin una instancia para llamar estáticamente, pero Clojure está tipeado dinámicamente, así que apuntaré esto a una diferencia de estilo entre los dos. idiomas en lugar de una ventaja particular de una manera u otra. También, por supuesto, es la ventaja de que las clases de tipo tienen mucho menos sobrecarga que los métodos múltiples ya que generalmente el registro del testigo puede estar en línea y todo se resuelve estáticamente.

En términos más generales, esta pregunta se refiere a varios enfoques del problema de la expresión . La idea es que su programa sea una combinación de un tipo de datos y operaciones sobre él. Queremos poder agregar nuevos casos sin volver a compilar las clases antiguas.

Ahora Haskell tiene algunas soluciones realmente increíbles para el problema de expresión con TypeClass . En particular, podemos hacer:

class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool member :: (Eq a) => a -> [a] -> Bool member y [] = False member y (x:xs) = (x == y) || member y xs

Ahora en Clojure hay multimétodos , por lo que puedes hacer:

(defmulti area :Shape) (defn rect [wd ht] {:Shape :Rect :wd wd :ht ht}) (defn circle [radius] {:Shape :Circle :radius radius}) (defmethod area :Rect [r] (* (:wd r) (:ht r))) (defmethod area :Circle [c] (* (. Math PI) (* (:radius c) (:radius c)))) (defmethod area :default [x] :oops) (def r (rect 4 13)) (def c (circle 12)) (area r) -> 52 (area c) -> 452.3893421169302 (area {}) -> :oops

También en Clojure tienes protocolos , con los que puedes hacer:

(defprotocol P (foo [x]) (bar-me [x] [x y])) (deftype Foo [a b c] P (foo [x] a) (bar-me [x] b) (bar-me [x y] (+ c y))) (bar-me (Foo. 1 2 3) 42) => 45 (foo (let [x 42] (reify P (foo [this] 17) (bar-me [this] x) (bar-me [this y] x)))) => 17

Ahora este individuo hace el reclamo :

Pero, hay protocolos y métodos múltiples. Estos son muy poderosos, pero no tan poderosos como las clases de tipos de Haskell. Puede introducir algo así como una clase de letra especificando su contrato en un protocolo. Esto solo se distribuye en el primer argumento, mientras que Haskell puede enviarlo en toda la firma, incluido el valor de retorno. Los métodos múltiples son más potentes que los protocolos, pero no tan potentes como el envío de Haskell.

Mi pregunta es: ¿Cuáles son las razones por las que los protocolos y los métodos multimétodos en Clojure son menos potentes para el polimorfismo que las clases de tipos en Haskell?


La diferencia más fundamental es que con las clases de tipo, el despacho está en tipos no en valores . No se necesita ningún valor para realizarlo. Eso permite casos mucho más generales. El ejemplo más obvio es el envío en (parte de) el tipo de resultado de una función. Considere, por ejemplo, la clase de lectura de Haskell:

class Read a where readsPrec :: Int -> String -> [(a, String)] ...

Tal envío es claramente imposible con los métodos múltiples, que tienen que enviar en sus argumentos.

Ver también mi comparación más extensa con OO simple .