¿Qué tan práctico es incrustar el núcleo de un lenguaje con un espacio de funciones efectivo(como ML) en Haskell?
f# ocaml (1)
Here es una forma posible, por sigfpe. No cubre las lambdas, pero parece que puede extenderse a ellas.
Como propuso Moggi hace 20 años, el espacio de funciones efectivo ->
de lenguajes como ML se puede descomponer en el espacio de funciones total estándar =>
más una monada T
fuerte para capturar efectos.
A -> B
descompone en A => (TB)
Ahora, Haskell admite mónadas, incluida una mónada IO que parece suficiente para los efectos en ML, y tiene un espacio de funciones que contiene => (pero también incluye funciones parciales). Por lo tanto, deberíamos poder traducir un fragmento considerable de ML en Haskell a través de esta descomposición. En teoría creo que esto funciona.
Mi pregunta es si una incrustación como esta puede ser práctica: ¿es posible diseñar una biblioteca de Haskell que permita la programación en Haskell en un estilo no muy alejado de ML? Y si es así, ¿cómo será el rendimiento?
Mi criterio para "práctico" es que el código ML existente con un uso extensivo de los efectos podría transcribirse de forma relativamente fácil a Haskell a través de la incorporación, incluidos los casos complicados que involucran funciones de orden superior.
Para concretar esto, a continuación se muestra mi propio intento de realizar tal transcripción a través de la inserción. La función principal es una transcripción de un código ML simple que genera de manera imperativa 5 nombres de variables distintas. En lugar de utilizar la descomposición directamente, mi versión levanta las funciones para que evalúen sus argumentos: las definiciones anteriores a main
son una mini biblioteca que incluye primitivas elevadas. Esto funciona bien, pero algunos aspectos no son totalmente satisfactorios.
- Hay demasiado ruido sintáctico para la inyección de valores en los cálculos a través de
val
. Tener versiones de funciones sinrdV
(comordV
) ayudaría a esto, al costo de requerir que estas estén definidas. - Las definiciones sin valor como
varNum
requieren vinculación monádica mediante<-
en undo
. Esto obliga a cualquier definición que dependa de ellos a estar también en la misma expresión. - Parece entonces que todo el programa podría terminar en una gran expresión. Así es como a menudo se consideran los programas de LD, pero en Haskell no está tan bien soportado, por ejemplo, estás obligado a usar el
case
lugar de las ecuaciones. - Supongo que habrá algo de pereza a pesar de enhebrar la mónada IO en todo momento. Dado que el programa de LD se diseñaría para una evaluación estricta, probablemente debería eliminarse la pereza. Sin embargo, no estoy seguro de cuál es la mejor manera de hacer esto.
Entonces, ¿algún consejo sobre cómo mejorar esto, o sobre mejores enfoques que usen la misma descomposición, o incluso maneras muy diferentes de lograr el mismo objetivo general de programación en Haskell usando un estilo que refleje ML? (No es que no me guste el estilo de Haskell, es solo que me gustaría poder asignar fácilmente el código ML existente).
import Data.IORef
import Control.Monad
val :: Monad m => a -> m a
val = return
ref = join . liftM newIORef
rdV = readIORef -- Unlifted, hence takes a value
(!=) r x = do { rr <- r; xx <- x; writeIORef rr xx }
(.+),(.-) :: IO Int -> IO Int -> IO Int
( (.+),(.-) ) = ( liftM2(+), liftM2(-) )
(.:) :: IO a -> IO [a] -> IO [a]
(.:) = liftM2(:)
showIO :: Show a => IO a -> IO String
showIO = liftM show
main = do
varNum <- ref (val 0)
let newVar = (=<<) $ /() -> val varNum != (rdV varNum .+ val 1) >>
val ''v'' .: (showIO (rdV varNum))
let gen = (=<<) $ /n -> case n of 0 -> return []
nn -> (newVar $ val ()) .: (gen (val n .- val 1))
gen (val 5)