haskell

haskell - ¿Agregar ceros entre elementos en la lista?



(6)

Aquí podemos hacer uso de un patrón foldr donde para cada elemento en la lista original, lo anteponemos con un 0 :

addZeros :: Num a => [a] -> [a] addZeros [] = [] addZeros (x:xs) = x : foldr (((0 :) .) . (:)) [] xs

Estoy tratando de cambiar una lista en haskell para incluir 0 entre cada elemento. Si tenemos la lista inicial [1..20] , me gustaría cambiarla a [1,0,2,0,3..20]

Lo que pensé hacer es usar el mapa en cada función, extraer el elemento y luego agregarlo a la lista y usar ++[0] , pero no estoy seguro de si este es el enfoque correcto o no. Todavía estoy aprendiendo haskell, por lo que podría tener errores.

Mi código:

x = map classify[1..20] classify :: Int -> Int addingFunction 0 [Int] addingFunction :: Int -> [a] -> [a] addingFunction x xs = [a] ++ x ++ xs


Con una coincidencia de patrones simple, debería ser:

addingFunction n [] = [] addingFunction n [x] = [x] addingFunction n (x:xs) = x: n : (addingFunction n xs) addingFunction 0 [1..20] => [1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20]


No puedes hacer esto con el map . Una de las propiedades fundamentales del map es que su salida siempre tendrá exactamente tantos elementos como su entrada, porque cada elemento de salida corresponde a una entrada, y viceversa.

Sin embargo, hay una herramienta relacionada con la potencia necesaria:

concatMap :: (a -> [b]) -> [a] -> [b]

De esta manera, cada elemento de entrada puede producir cero o más elementos de salida. Puede usar esto para construir la función que desea:

between :: a -> [a] -> [a] sep `between` xs = drop 1 . concatMap insert $ xs where insert x = [sep, x] 0 `between` [1..10] [1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10]

O una definición más concisa de between :

between sep = drop 1 . concatMap ((sep :) . pure)


Si desea utilizar el map para resolver esto, puede hacer algo como esto:

Tenga una función que obtenga un int y devuelva una lista de 2 elementos con int y cero:

addZero :: List addZero a = [0, a]

Entonces puede llamar al mapa con esta función:

x = map addZero [1..20] -- this will return [[0,1], [0, 2] ...]

Notarás que es una lista anidada. Así es como funciona el map . Necesitamos una forma de combinar la lista interna en una sola lista. Este caso usamos foldl

combineList :: [[Int]] -> [Int] combineList list = foldl (++) [] list -- [] ++ [0, 1] ++ [0, 2] ...

Entonces, la forma en que foldl funciona en este caso es que acepta una función de combinación, un valor inicial y la lista para combinar.

Como no necesitamos el primer 0, podemos soltarlo:

dropFirst :: [Int] -> [Int] dropFirst list = case list of x:xs -> xs [] -> []

Código final:

x = dropFirst $ combineList $ map addZero [1..20] addZero :: Int -> [Int] addZero a = [0, a] combineList :: [[Int]] -> [Int] combineList list = foldl (++) [] list dropFirst :: [Int] -> [Int] dropFirst list = case list of x:xs -> xs [] -> []


Si no quieres usar entre intersperse , puedes escribir el tuyo.

intersperse :: a -> [a] -> [a] intersperse p as = drop 1 [x | a <- as, x <- [p, a]]

Si lo desea, puede usar las operaciones Applicative :

import Control.Applicative intersperse :: a -> [a] -> [a] intersperse p as = drop 1 $ as <**> [const p, id]

Esta es básicamente la definición utilizada en Data.Sequence .


intersperse está hecho para esto. Simplemente import Data.List (intersperse) , luego intersperse 0 yourList .