título titulo sirve que para etiqueta scala haskell programming-languages functional-programming type-systems

scala - titulo - ¿Se puede implementar esta funcionalidad con el sistema de tipos de Haskell?



para que sirve la etiqueta title (3)

En Scala, las operaciones de orden superior en las colecciones siempre devuelven el mejor tipo posible en el contexto. Por ejemplo, en el caso de BitSet , si BitSet a BitSet obtiene un BitSet , pero si BitSet a cadenas, obtendrá un Set general. Del mismo modo, si map un Map con una función que produce un par, obtendrá un Map a cambio. De lo contrario obtienes un simple Iterable . Tanto el tipo estático como la representación en tiempo de ejecución del resultado del mapa dependen del tipo de resultado de la función que se le pasa.

scala> Map(2 -> ''a'', 6 -> ''b'') map { case (k, v) => (k + 1, v.toString) } res0: scala.collection.immutable.Map[Int,java.lang.String] = Map(3 -> a, 7 -> b) scala> Map(2 -> ''a'', 6 -> ''b'') map { _._1 } res1: scala.collection.immutable.Iterable[Int] = List(2, 6) scala> import collection.immutable.BitSet import collection.immutable.BitSet scala> BitSet(2, 44, 93).map(1 +) res3: scala.collection.immutable.BitSet = BitSet(3, 45, 94) scala> BitSet(2, 44, 93).map(_ + "hola") res4: scala.collection.immutable.Set[String] = Set(2hola, 44hola, 93hola)

¿Es posible implementar la misma funcionalidad en el sistema de tipos de Haskell? Si es así, ¿cómo? Una traducción de Haskell de los ejemplos en el fragmento de código anterior sería muy apreciada. :-)


Agregando a Hammar: creo que el segundo ejemplo no es posible tal como está, porque hay conversiones de tipos implícitas.

Ignorando eso por el bien de la discusión, ¿cómo podría ser la firma de tipo?

setmap :: (Set a, Set b) => a e -> (e -> f) -> b f

Entonces, sí, esto es concebible, pero con la disposición de que uno puede necesitar especificar el tipo de retorno.


Estoy muy de acuerdo con Hammar, pero aquí hay una forma de hacerlo:

{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-} import Prelude hiding (map) import qualified Data.Map as M import qualified Data.IntSet as I import qualified Data.Set as S type family Elem c :: * type instance Elem (M.Map k v) = (k, v) type instance Elem I.IntSet = Int type instance Elem (S.Set a) = a class Map c o where type Result c o :: * map :: (Elem c -> o) -> c -> Result c o instance Map I.IntSet Int where type Result I.IntSet Int = I.IntSet map = I.map instance Map I.IntSet String where type Result I.IntSet String = S.Set String map f = S.fromList . fmap f . I.toList instance (Ord k, Ord k1) => Map (M.Map k v) (k1, v1) where type Result (M.Map k v) (k1, v1) = M.Map k1 v1 map f = M.fromList . fmap f . M.toList instance (Ord k) => Map (M.Map k v) Int where type Result (M.Map k v) Int = [Int] map f = fmap f . M.toList

Aquí está en acción:

*Main> map fst (M.fromList [(2::Int, ''a''), (6, ''b'')]) [2,6] *Main> map (/(k, v) -> (k + 1, show v)) (M.fromList [(2, ''a''), (6, ''b'')]) fromList [(3,"''a''"),(7,"''b''")] *Main> :t it it :: M.Map Integer [Char]

Lo ideal sería hacer esto:

instance (Ord k) => Map (M.Map k v) a where type Result (M.Map k v) a = [a] map f = fmap f . M.toList

Pero esa instancia entra en conflicto con la de las parejas. Así que no hay una buena manera de dar una instancia para cada otro tipo.


No creo que tu primer ejemplo sea muy Haskell-y, ya que estás sobrecargando el mismo nombre para hacer dos cosas muy diferentes. En Haskell, cuando asigna una función a un contenedor, espera recuperar el mismo tipo de contenedor. De hecho, esto es tan común en Haskell que existe una clase de tipo, Functor que encapsula este patrón.

Todas las formas de sobrecarga en Haskell se reducen a usar clases de tipos, y aunque podría usarlas para lograr algo similar, sería muy artificial y no muy útil solo con el uso de funciones simples que hacen lo que usted desea.

Prelude> import qualified Data.Map as M Prelude Data.Map> let m = M.fromList [(2, ''a''), (6, ''b'')] Prelude Data.Map> M.map show $ M.mapKeys (+1) m fromList [(3,"''a''"),(7,"''b''")] Prelude Data.Map> M.keys m [2,6]

Creo que su segundo ejemplo es más relevante para Haskell, ya que se trata más de elegir la implementación más eficiente de una estructura de datos basada en el tipo contenido, y sospecho que no debería ser demasiado difícil hacerlo con familias de tipos , pero No estoy demasiado familiarizado con esos, así que dejaré que alguien más intente responder esa parte.