2010-10-23 11 views
6

Estoy escribiendo un juego de serpientes en Haskell. Estas son algunas de las cosas que tengo:¿Qué tan pequeño debería hacer hacer módulos en Haskell?

  • Un tipo de datos Coord
  • Un tipo de datos Line
  • Un tipo de datos Rect
  • Una clase Polygon tipo, lo que me permite obtener un Rect como serie de líneas ([Line]).
  • Una clase de tipo Impassable que me permite obtener un Line como una serie de Coords ([Coord]) para que pueda detectar colisiones entre otras Impassable s.
  • A Draw tipo de clase para todo lo que quiero dibujar en la pantalla (HSCurses).
  • Finalmente estoy usando QuickCheck así que quiero declarar Arbitrary instancias para muchas de estas cosas.

Actualmente tengo muchos de estos en módulos separados, así que tengo muchos módulos pequeños. Me he dado cuenta de que tengo que importar muchos de ellos el uno al otro, así que me pregunto cuál fue el punto.

Estoy especialmente confundido acerca de las instancias Arbitrary. Cuando utilizo -Wall recibo advertencias sobre instancias huérfanas cuando solo las instancias juntas en un archivo de prueba, entiendo que puedo evitar esa advertencia colocando esas instancias en el mismo módulo donde se define el tipo de datos, pero luego necesitaré a import Test.QuickCheck para todos esos módulos que parece tonto porque QuickCheck solo debería ser requerido al construir el ejecutable de prueba.

Cualquier consejo sobre el problema específico con QuickCheck sería apreciado como lo haría la orientación sobre el problema más general de cómo/dónde los programas deberían dividirse en módulos.

Respuesta

1

Generalmente pongo más énfasis en la interfaz del módulo como se define por las funciones que expone en lugar de los tipos de datos que expone. ¿Algunos de tus tipos comparten un conjunto común de funciones? Luego los pondría en el mismo módulo.

Pero mi práctica probablemente no sea la mejor ya que generalmente escribo pequeños programas. Aconsejaría buscar algún código en Hackage para ver qué hacen los mantenedores.

Si hubiera una manera de ordenar paquetes por clasificación de comunidad o número de descargas, sería un buen lugar para comenzar. (Pensé que sí, pero ahora que lo busco, no puedo encontrarlo). De lo contrario, observe los paquetes que ya usa.

+0

Hay enlaces para clasificaciones por número de descargas y número de dependencias inversas aquí: http://stackoverflow.com/questions/3663550/which-haskell-package-for-json/3663601#3663601 –

4

Puedes tener tu pastel y comértelo también. Puede volver a exportar módulos.

module Geometry 
    (module Coord, module Line, module Rect, module Polygon, module Impassable) 
where 

que suelo utilizar un módulo cada vez que tengo una abstracción completa - es decir, cuando el significado de un tipo de datos difiere de su aplicación. Sabiendo poco acerca de su código, probablemente agruparía Polygon y Impassable juntos, quizás haciendo un tipo de datos Collision para representar lo que devuelven. Pero Coord, Line y Rect parecen buenas abstracciones y probablemente se merecen sus propios módulos.

+0

Cualquier sugerencia que hacer sobre el problema QuickCheck? –

+1

Ese es un problema difícil, en el que he estado trabajando en realidad. Creo que tu mejor opción ahora es tratar con los huérfanos como sugiere John. Creo que la forma correcta de hacerlo es tener "combinators de distribución", así que en lugar de 'instance Arbitrary Coord', tienes una función' arbitraryCoord :: Distribution Coord'. Es un poco más complicado de usar en las pruebas, pero es más flexible y modular, ya que puede tener múltiples distribuciones para el mismo tipo (en particular, si se definen dos distribuciones diferentes, el mundo no explota). – luqui

2

Para fines de prueba, uso módulos separados para las instancias Arbitrary. Aunque generalmente evito instancias huérfanas, estos módulos solo se construyen cuando se construye el ejecutable de prueba, por lo que no me importan los huérfanos o que no está limpio -Wall. También puede usar -fno-warn-orphans para deshabilitar solo este mensaje de advertencia.

+0

Tiene un módulo separado para _todas las instancias 'Arbitrary'? –

+0

@Ollie Saunders: depende del tamaño del proyecto. Para proyectos más pequeños, utilizo dos módulos para probar: uno tiene instancias 'Arbitrary' y otro código adicional si es necesario, y el otro módulo tiene las propiedades QuickCheck. Para proyectos más grandes, me gusta el diseño utilizado en el marco de Snap. Tienen un módulo de prueba para cada módulo regular que incluye instancias arbitrarias y pruebas de propiedades. –

0

Una solución con QuickCheck es usar el preprocesador C para activar selectivamente las instancias arbitrarias cuando está realizando la prueba. Coloque las instancias arbitrarias directamente en sus módulos principales, pero envuélvalas con macros de preprocesador, luego coloque una bandera de "prueba" en su archivo Cabal.

Cuestiones relacionadas