talk by Bret Victor'un bir videosunu izledikten sonra, konuşmasında gösterdiği bir gelişim ortamına benzeyen hızlı bir hack yazmaktan ilham aldım.Veri türlerimi Haskell'de bir yeniden derlemeye neden olmadan nasıl değiştirebilirim?
Temel olarak fikir, bir uygulamanın bir pencerede çalıştığı ve bir kaynak dosyada bir değişiklik kaydedildiği zaman programın değişmesidir.
Bu, uygulamayı kapatmadan ve yeniden derlemeye gerek kalmadan kodumdaki durumun türünü değiştirememenin dışında küçük değişiklikler için harika çalışıyor.
İfade sorununu nasıl çözebilirim ve durumumun veri türü 'u yeniden derlenmeden değiştirebilir mi?
P.S. İşte kod. Aslen postalamak istemedim çünkü gerçekten dağınık ve çabuk bir şekilde hacklenmişti, ama insanlar istediler, böylece onu alabilirler.
İlk önce ekran ve boşta kalan modül, (bu, hızlı bir şekilde kesilmişti, bu yüzden bunları gerçek modüller olarak nasıl yapacağımı anlamadım).
Idle.hs
\state -> do
counter <- readIORef state
writeIORef state ((counter + 1)`mod`3)
postRedisplay Nothing
Display.hs
\state -> let
cube w = do
renderPrimitive Quads $ do
vertex $ Vertex3 w w w
vertex $ Vertex3 w w (-w)
vertex $ Vertex3 w (-w) (-w)
vertex $ Vertex3 w (-w) w
vertex $ Vertex3 w w w
vertex $ Vertex3 w w (-w)
vertex $ Vertex3 (-w) w (-w)
vertex $ Vertex3 (-w) w w
vertex $ Vertex3 w w w
vertex $ Vertex3 w (-w) w
vertex $ Vertex3 (-w) (-w) w
vertex $ Vertex3 (-w) w w
vertex $ Vertex3 (-w) w w
vertex $ Vertex3 (-w) w (-w)
vertex $ Vertex3 (-w) (-w) (-w)
vertex $ Vertex3 (-w) (-w) w
vertex $ Vertex3 w (-w) w
vertex $ Vertex3 w (-w) (-w)
vertex $ Vertex3 (-w) (-w) (-w)
vertex $ Vertex3 (-w) (-w) w
vertex $ Vertex3 w w (-w)
vertex $ Vertex3 w (-w) (-w)
vertex $ Vertex3 (-w) (-w) (-w)
vertex $ Vertex3 (-w) w (-w)
points :: Integer -> [(GLfloat,GLfloat,GLfloat)]
points n' = let n = fromIntegral n' in map (\k -> let t = 2*pi*k/n in (sin(t),cos(t),0.0)) [1..n]
in do
clear [ ColorBuffer ]
counter <- readIORef state
mapM_ (\(x,y,z) -> preservingMatrix $ do
color $ Color3 ((x+1.0)/2.0) ((y+1.0)/2.0) ((z+1.0)/2.0)
translate $ Vector3 x y z
cube (0.3::GLfloat)
) $ points (9 + counter)
flush
ana modül
module Main where
import Control.Monad
import Data.Typeable as Typeable
import System.IO
import Data.IORef
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
import Language.Haskell.Interpreter
main :: IO()
main = do
(_, _) <- getArgsAndInitialize
createWindow "Hello World"
action <- newIORef $ do
clear [ ColorBuffer ]
flush
let imports = ["Prelude", "Data.IORef", "Graphics.Rendering.OpenGL", "Graphics.UI.GLUT"]
let modules = ["State"]
runFile (undefined :: IORef Integer -> IO()) "Display.hs" imports $ \displayCode ->
runFile (undefined :: IORef Integer -> IO()) "Idle.hs" imports $ \idleCode -> do
state <- newIORef 12
displayCallback $= display displayCode state
idleCallback $= Just (idle displayCode idleCode state)
mainLoop
display displayCode state = do
f <- execute displayCode
f state
idle displayCode idleCode state = do
update displayCode
update idleCode
f <- execute idleCode
f state
instance Eq GhcError where
GhcError s == GhcError t = s == t
instance Eq InterpreterError where
UnknownError s == UnknownError t = s == t
WontCompile s == WontCompile t = s == t
NotAllowed s == NotAllowed t = s == t
GhcException s == GhcException t = s == t
data V a = V {
update :: IO(),
execute :: IO a
}
runFile :: Typeable a => a -> String -> [String] -> (V a -> IO()) -> IO()
runFile theType file imports f = do
currentError <- newIORef Nothing
currentAction <- newIORef Nothing
let v = V {
update = do
fileContents <- readFile file
result <- runInterpreter $ do
setImports imports
interpret fileContents theType
oldError <- readIORef currentError
case result of
Right newAction -> do
when (oldError /= Nothing) $ do
writeIORef currentError Nothing
putStrLn (file ++ " Ok!")
writeIORef currentAction (Just newAction)
Left newError -> do
when ((Just newError) /= oldError) $ do
writeIORef currentError (Just newError)
print newError
, execute = do
action <- readIORef currentAction
case action of
Nothing -> do
err <- readIORef currentError
return (error (show err))
Just act -> return act
}
update v
f v
+1. Kodunuzu bir yere gönderebilirseniz harika olur. Statik olarak yazılan bir dilin böyle bir ortam için çok uygun olmadığını düşünüyorum. Statik türlerde ısrar ederseniz, çalışma zamanı (en azından hata ayıklama geliştirme çalışma zamanı) statik türleri atmalı ve dinamik türlerle çalışmalıdır. Haskell için böyle bir çalışma zamanı olduğundan emin değilim. –
@ user990666 Bağlantıyı konuşmaya gönderebilir misiniz? –
@Matt Fenwick http://vimeo.com/36579366 –