tipos por pattern opciones hacer funciones ejemplos datos contador como ciclos casos list haskell

list - por - string en haskell



¿Cómo comprimir varias listas en Haskell? (9)

En Python, la función zip acepta un número arbitrario de listas y las comprime.

>>> l1 = [1,2,3] >>> l2 = [5,6,7] >>> l3 = [7,4,8] >>> zip(l1,l2,l3) [(1, 5, 7), (2, 6, 4), (3, 7, 8)] >>>

¿Cómo puedo zip varias listas en haskell?


Creo que es probablemente la solución menos elegante sugerida, pero en aras de la integridad debería agregarse que esas cosas deberían ser posibles con Template Haskell.

De hecho, esto se trató en lo que creo que es el documento de la plantilla de Haskell original (busque zipn en el texto): http://research.microsoft.com/en-us/um/people/simonpj/Papers/meta-haskell/meta-haskell.pdf

Pero creo que el código nunca funcionó, vea esto: http://www.haskell.org/pipermail/template-haskell/2003-July/000126.html (no se implementan los cortes de patrón).

Eso no se implementó en 2003, pero todavía no se implementó hoy: http://www.haskell.org/ghc/docs/7.6.1/html/users_guide/template-haskell.html (no se admiten los cortes de patrón)

Sin embargo, hay una implementación de zipWithN utilizando la plantilla haskell: http://www.haskell.org/haskellwiki/Template_Haskell#zipWithN

He verificado que funciona con este programa de prueba:

{-# LANGUAGE TemplateHaskell #-} import Zipn main = do let l1 = [1,2,3] let l2 = [5,6,7] let l3 = [7,4,8] print $ $(zipWithN 3) (,,) l1 l2 l3

En el módulo Zipn, pegué el archivo zipn, simplemente renombré zipWithN para mayor claridad (y recuerda agregar el Pragma TemplateHaskell en la parte superior). Tenga en cuenta que la N está de hecho codificada dos veces aquí, porque tuve que dar (,,) como la función "con". Tendrías que cambiar el número de comas dependiendo de N.

(,,) significa /abc -> (a,b,c)

Supongo que alguien con buenas habilidades de Template Haskell (que no es mi caso en este punto) podría hacer un zipN directo utilizando Template Haskell.


La generalización de la compresión es bastante fácil. Solo tiene que escribir versiones especializadas de los combinadores ZipList para ZipList :

z :: [a -> b] -> [a] -> [b] z = zipWith ($) infixl 4 `z`

Ahora puedes comprimir tantas listas como quieras:

f <$> xs `z` ys `z` zs

o alternativamente:

repeat f `z` xs `z` ys `z` zs


No es trivial, pero es factible. Ver esta entrada de blog . No sé si esto se hizo en alguna biblioteca.

Aquí hay otra versión , que es más sencilla. Este podría ser cortado y pegado aquí:

{-# LANGUAGE MultiParamTypeClasses , FunctionalDependencies , FlexibleInstances , UndecidableInstances #-} -- | -- Module : Data.List.ZipWithN -- Copyright : Copyright (c) 2009 wren ng thornton -- License : BSD3 -- Maintainer : [email protected] -- Stability : experimental -- Portability : non-portable (MPTCs, FunDeps,...) -- -- Provides a polyvariadic ''map''/''zipWith'' like the @map@ in Scheme. -- For more details on this style of type hackery, see: -- -- * Chung-chieh Shan, /A polyvariadic function of a non-regular/ -- /type (Int->)^N ([]^N e)->.../ -- <http://okmij.org/ftp/Haskell/polyvariadic.html#polyvartype-fn> ---------------------------------------------------------------- module Data.List.ZipWithN (ZipWithN(), zipWithN) where -- | This class provides the necessary polymorphism. It is only -- exported for the sake of giving type signatures. -- -- Because we can''t do functor composition without a lot of noise -- from newtype wrappers, we use @gr@ and @kr@ to precompose the -- direct/list functor with the reader functor and the return type. class ZipWithN a gr kr | kr -> gr a where _zipWithN :: [a -> gr] -> [a] -> kr instance ZipWithN a b [b] where _zipWithN = zipWith ($) instance ZipWithN b gr kr => ZipWithN a (b -> gr) ([b] -> kr) where _zipWithN = (_zipWithN .) . zipWith ($) -- | Polyadic version of ''map''/''zipWith''. The given type signature -- isn''t terribly helpful or intuitive. The /real/ type signature -- is: -- -- > zipWithN :: {forall a}^N. ({a->}^N r) -> ({[a]->}^N r) -- -- Note that the @a@ type variables are meta and so are independent -- from one another, despite being correlated in N across all -- repetitions. zipWithN :: (ZipWithN a gr kr) => (a -> gr) -> [a] -> kr zipWithN = _zipWithN . repeat

Si recién estás comenzando a aprender Haskell, pospóntalo por un tiempo :)


Para un número específico de listas, puedes hacer algo como esto:

> let l1 = [1,2,3] > let l2 = "abc" > let l3 = [10.0, 11.0, 12.0] > let l4 = [True, False, False] > [ (e1,e2,e3,e4) | (((e1,e2),e3),e4) <- zip (zip (zip l1 l2) l3) l4 ] [(1,''a'',10.0,True),(2,''b'',11.0,False),(3,''c'',12.0,False)]

No es una función genérica, sino un patrón que puede aplicar a un número diferente de listas.


Parece que también hay un zip3 ( doc ) y una función zip4 ( doc ) en Haskell. Pero el zipn parece ser complicado debido al sistema de tipo fuerte. Aquí hay una buena discusión que he encontrado durante mi investigación.


Puedes transponer una lista de listas:

>>> import Data.List >>> transpose [l1,l2,l3] [[1,5,7],[2,6,4],[3,7,8]]


Se puede lograr una generalización de zip usando Notación Aplicativa . Es un poco desagradable de usar debido al nuevo tipo de envoltura / desenvolvimiento, pero si está haciendo algo que no se puede hacer con un zipWithn para una n razonablemente pequeña, es probable que ya esté en un nivel de abstracción suficientemente alto donde están los dolores notacionales. ausente de todos modos

El tipo es ZipList a , y su instancia aplicativa se ZipList a . Por ejemplo:

(+) <$> ZipList [1,2] <*> ZipList [3,4] == ZipList [4,6]

Esto generaliza a funciones de aridad arbitraria y tipo usando aplicación parcial:

(+) <$> ZipList [1,2] :: ZipList (Int -> Int)

¿Ves cómo (+) se aplica parcialmente aquí?

Si no le gusta agregar ZipList y getZipList en todas partes, puede recrear la notación con la suficiente facilidad:

(<$>) :: (a -> b) -> [a] -> [b] (<$>) = map (<*>) :: [a -> b] -> [a] -> [b] (<*>) = zipWith ($)

Entonces la notación para zipWith fabcd ... es:

f <$> a <*> b <*> c <*> d <*> ...

La notación aplicativa es una técnica muy poderosa y general que tiene un alcance mucho más amplio que la simple compresión generalizada. Consulte la Typeclassopedia para más información sobre la notación aplicativa.


Si todos tus datos son del mismo tipo que podrías hacer:

import Data.List (transpose) zipAllWith :: ([a] -> b) -> [[a]] -> [b] zipAllWith _ [] = [] zipAllWith f xss = map f . transpose $ xss zipAll = zipAllWith id

Ejemplo:

> zipAll [[1, 2, 3], [4, 5, 6], [7, 8]] [[1,4,7],[2,5,8],[3,6]]


GHC también apoya la comprensión de listas paralelas :

{-# LANGUAGE ParallelListComp #-} [(x,y) | x <- [1..3] | y <- [''a''..''c''] ] ==> [(1,''a''),(2,''b''),(3,''c'')]

Acabo de probar hasta 26 variables paralelas, lo que debería ser suficiente para todos los propósitos prácticos.

Sin embargo, es un poco hacky (y no estándar), por lo que en caso de que estés escribiendo algo serio, ZipList puede ser la mejor manera de hacerlo.