functions drop haskell list-comprehension applicative

drop - haskell types



¿Cuáles son algunas formas mejores de escribir[(-1,-1),(- 1,0),(- 1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] en Haskell? (7)

¿Por qué no usar simplemente una lista de comprensión? Pueden tener guardias booleanas, por lo que excluir (0,0) es bastante simple:

[(i,j) | i <- [-1..1], j <- [-1..1], (i,j) /= (0,0)]

Tenga en cuenta que como nuevo Haskell, probablemente haya una forma más compacta / eficiente de escribir esa expresión de guarda. Sin embargo, esto hace el trabajo.

Me he encontrado en algunas situaciones donde necesito la lista:

[(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] -- no (0,0)

Tenga en cuenta que no hay (0,0) en la lista. Utilizo las tuplas (dx, dy) para buscar hacia arriba, abajo, izquierda, derecha y en diagonal desde una coordenada.

Cada vez que lo escribo, siento que debería haber una forma más concisa y / o más fácil de leer para definirlo. Soy relativamente nuevo en Haskell y creo que en algún lugar de la bolsa de los trucos de Applicative / Functor / Monad debería haber una buena manera de hacerlo.

He intentado:

[(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]

A veces es mejor escribirlo, pero no creo que esta sea una de esas veces. No es obvio con una mirada que (0,0) no está incluido, y hay que leerlo un poco para notar el patrón.

map (/[a,b] -> (a,b)) $ delete [0,0] $ sequence $ replicate 2 [-1,0,1]

Me gusta el de arriba porque puedo poner el "2" allí, que es una buena forma explícita de decir "Estamos haciendo el mismo tipo de cosas dos veces", pero no puedo aceptar el mapa al frente con el gran Lambda insegura y 2 nombres.

[(dx,dy) | let a = [-1,0,1], dx <- a, dy <- a, (dx,dy) /= (0, 0)]

Este tiene demasiados nombres, pero usa la comprensión de la lista exactamente como está diseñada. Puede ser más fácil de leer para alguien a quien realmente le gustan las listas de comprensión, pero no me gustan todos los nombres.

let x = [-1,0,1] in delete (0,0) $ (,) <$> x <*> x

Esa parece más bonita, pero no tengo ese "2" ahí, y tengo un nombre. Este es mi favorito hasta ahora, pero no se siente perfecto.

Creo que si entendiera cómo escribir esto mejor podría tener una comprensión más profunda de los Functors / Monads o similares. He leído un poco sobre ellos, y he escuchado un montón de palabras como fmap / mconcat / etc, pero no sé cuál es el que debo tomar en esta situación.


Aquí hay una versión concisa usando cosas de Control.Applicative :

delete (0, 0) $ (,) <$> [-1..1] <*> [-1..1]

Personalmente, creo que esto se ve mucho mejor usando & , que es solo $ invertido.

(,) <$> [-1..1] <*> [-1..1] & delete (0, 0)

También puede usar liftA2 lugar de <$> y <*> :

liftA2 (,) [-1..1] [-1..1] & delete (0, 0)

Está definido en la biblioteca de lentes, entre otros lugares, pero puede definirlo usted mismo:

infixl 1 & x & f = f x

Dicho todo esto, sigo prefiriendo la versión con la lista de comprensión o incluso la lista literal con una buena sangría.


En realidad, creo que es mejor escribirlo explícitamente en este caso. Simplemente alinéelo razonablemente, y ninguna pregunta quedará abierta de ninguna manera:

neighbours = [ (-1,-1), (-1,0), (-1,1) , ( 0,-1), ( 0,1) , ( 1,-1), ( 1,0), ( 1,1) ]

No hay forma de que una alternativa pueda explicarse más que esto.

Por supuesto, hay alternativas más concisas . Siendo un chico de física, yo tendería a

[ (round $ - sin φ, round $ - cos φ) | φ <- [pi/4, pi/2 .. 2*pi] ]

lo que, por supuesto, es más caro de computar, pero eso no importa si solo define esta lista en un lugar y la reutiliza desde todos sus programas. El orden es diferente aquí, no estoy seguro de si eso importa.


Para una lectura más fácil puedes probar:

left = (-1,0) right = (1,0) up = (0,1) down = (0,-1) --etc directions = [left,right,up,down]

Estos son realmente vectores, por lo que es posible que desee considerar el uso de una biblioteca de vectores si tiene sentido en su aplicación, o crear sus propias operaciones de vectores personalizados:

import Data.Vect vecUp = Vec2 0,1 vecDown = Vec2 0,(-1) --etc. goUp10 = 10 *& vecUp -- ''*&'' is the scalar multiply operator


Prelude Data.Ix Data.List> delete (0,0) (range ((-1,-1),(1,1))) [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]


Prelude> let sqrt'' n | n == 0 = [0] | otherwise = [sqrt n, negate (sqrt n)] Prelude> [(x,y) | x <- [-1..1] , y <- sqrt'' (1 - x^2) ++ (if x==0 then [] else sqrt'' (2 - x^2))]


liftA2 zip (!!0) (!!1) . transpose . tail . replicateM 2 $ [0,1,-1]

(No es que yo recomiendo esto.)