palindromo modulos importar funciones español ejemplos haskell module cake-pattern

modulos - palindromo en haskell



¿Se puede implementar el patrón de pastel de Scala en Haskell? (3)

Hay varias soluciones. El "obvio" es tener varias instancias para determinadas clases de tipos (por ejemplo, Loader , Player , GUI para un juego) que pueden combinarse libremente, pero en mi opinión, tal diseño es más adecuado para los idiomas OO.

Si piensa fuera de la caja y reconoce que los bloques de construcción fundamentales en Haskell son funciones (¡D''oh!), Llegará a algo como esto:

data Game = Game { load :: String -> IO [Level] , player1 :: Level -> IO Level , player2 :: Level -> IO Level , display :: Level -> IO () } play :: Game -> IO ()

Con este diseño es muy fácil de reemplazar, por ejemplo, los jugadores humanos por robots. Si esto se vuelve demasiado complejo, usar la mónada Reader podría ser útil.

Mediante el uso de una serie de funciones de lenguaje más nuevas en Scala, es posible implementar un sistema de componentes compositivos y crear componentes utilizando el llamado Patrón de Torta, descrito por Martin Odersky en el resumen de componentes escalables de papel y también en una reciente charla .

Varias de las funciones de Scala utilizadas en el Patrón de la torta tienen características correspondientes de Haskell. Por ejemplo, las implicaciones de Scala corresponden a clases de tipo Haskell y los miembros de tipo abstracto de Scala parecen corresponder a los tipos asociados de Haskell. Esto me hace preguntarme si el Patrón de Torta podría implementarse en Haskell y cómo se vería.

¿Se puede implementar el patrón de torta en Haskell? ¿A qué características de Haskell corresponden las características de Scala en dicha implementación? Si no se puede implementar Cake Pattern en Haskell, ¿qué características de idioma faltan para que esto sea posible?



Tomando this como ejemplo, me parece que el siguiente código es bastante similar:

{-# LANGUAGE ExistentialQuantification #-} module Tweeter.Client where import Data.Time import Text.Printf import Control.Applicative import Control.Monad type User = String type Message = String newtype Profile = Profile User instance Show Profile where show (Profile user) = ''@'' : user data Tweet = Tweet Profile Message ZonedTime instance Show Tweet where show (Tweet profile message time) = printf "(%s) %s: %s" (show time) (show profile) message class Tweeter t where tweet :: t -> Message -> IO () class UI t where showOnUI :: t -> Tweet -> IO () sendWithUI :: Tweeter t => t -> Message -> IO () sendWithUI = tweet data UIComponent = forall t. UI t => UIComponent t class Cache t where saveToCache :: t -> Tweet -> IO () localHistory :: t -> IO [Tweet] data CacheComponent = forall t. Cache t => CacheComponent t class Service t where sendToRemote :: t -> Tweet -> IO Bool remoteHistory :: t -> IO [Tweet] data ServiceComponent = forall t. Service t => ServiceComponent t data Client = Client UIComponent CacheComponent ServiceComponent Profile client :: (UI t, Cache t, Service t) => t -> User -> Client client self user = Client (UIComponent self) (CacheComponent self) (ServiceComponent self) (Profile user) instance Tweeter Client where tweet (Client (UIComponent ui) (CacheComponent cache) (ServiceComponent service) profile) message = do twt <- Tweet profile message <$> getZonedTime ok <- sendToRemote service twt when ok $ do saveToCache cache twt showOnUI ui twt

Y para la implementación dummy:

module Tweeter.Client.Console where import Data.IORef import Control.Applicative import Tweeter.Client data Console = Console (IORef [Tweet]) Client console :: User -> IO Console console user = self <$> newIORef [] where -- Tying the knot here, i.e. DI of `Console'' into `Client'' logic is here. self ref = Console ref $ client (self ref) user instance UI Console where showOnUI _ = print -- Boilerplate instance: instance Tweeter Console where tweet (Console _ supertype) = tweet supertype instance Cache Console where saveToCache (Console tweets _) twt = modifyIORef tweets (twt:) localHistory (Console tweets _) = readIORef tweets instance Service Console where sendToRemote _ _ = putStrLn "Sending tweet to Twitter HQ" >> return True remoteHistory _ = return [] test :: IO () test = do x <- console "me" mapM_ (sendWithUI x) ["first", "second", "third"] putStrLn "Chat history:" mapM_ print =<< localHistory x -- > test -- Sending tweet to Twitter HQ -- (2012-10-21 15:24:13.428287 UTC) @me: first -- Sending tweet to Twitter HQ -- (2012-10-21 15:24:13.428981 UTC) @me: second -- Sending tweet to Twitter HQ -- (2012-10-21 15:24:13.429596 UTC) @me: third -- Chat history: -- (2012-10-21 15:24:13.429596 UTC) @me: third -- (2012-10-21 15:24:13.428981 UTC) @me: second -- (2012-10-21 15:24:13.428287 UTC) @me: first

Sin embargo, este es el caso más simple. En Scala tienes:

  • Clases con valor abstracto y miembros de tipo (recuerda a los funtores de ML y los registros dependientes, como en Agda).

  • Tipos dependientes del camino.

  • Linealización automática de clases.

  • esto y super

  • Autotipos.

  • Subtitulado.

  • Implícitos

  • ...

Es solo, bueno, diferente de lo que tienes en Haskell.