Sau khi xem video có số talk by Bret Victor, tôi đã được truyền cảm hứng để viết một bản hack nhanh tương tự như một môi trường phát triển mà ông đã trình bày trong buổi nói chuyện.Làm cách nào để thay đổi loại dữ liệu của mình mà không làm biên dịch lại trong Haskell?
Về cơ bản, ý tưởng là một ứng dụng chạy trong một cửa sổ và bất cứ khi nào một ứng dụng lưu thay đổi trong tệp nguồn chương trình sẽ thay đổi.
Điều này phù hợp với những thay đổi nhỏ, ngoại trừ việc tôi không thể thay đổi loại trạng thái trong mã của mình mà không tắt ứng dụng và biên dịch lại.
Làm cách nào để giải quyết vấn đề biểu thức và có kiểu dữ liệu của tiểu bang của tôi có thể thay đổi mà không gây ra biên dịch lại?
P.S. Đây là mã. Ban đầu tôi không muốn đăng vì nó thực sự lộn xộn và nhanh chóng bị tấn công cùng nhau, nhưng mọi người muốn nó để họ có thể nhận được nó.
Đầu tiên màn hình và mô-đun nhàn rỗi, (đây là một bản hack nhanh vì vậy tôi không tìm ra cách làm chúng như mô-đun thực).
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
Các module chính
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 cho diễn xuất trên trò chuyện của Bret Victor. Nó sẽ là tuyệt vời nếu bạn có thể đăng mã của bạn một nơi nào đó. Tôi nghĩ rằng một ngôn ngữ đánh máy tĩnh không phải là rất thích hợp cho một môi trường như thế này. Nếu bạn nhấn mạnh vào các kiểu tĩnh, thì thời gian chạy (thời gian chạy phát triển gỡ lỗi ít nhất) nên loại bỏ các kiểu tĩnh và làm việc với các kiểu động. Tôi không chắc chắn một thời gian chạy như thế này tồn tại cho Haskell. –
@ user990666 bạn có thể đăng liên kết tới bài nói chuyện không? –
@Matt Fenwick http://vimeo.com/36579366 –