I’m trying to kickstart my journey on Haskell and since I’m a game developer, I’ve been looking for books that lean towards interactive applications. I stumbled upon Paul Hudak’s Haskell School of Expression and it sounded like the perfect book, but I’ve been trying to set up an environment that would allow me to write and compile the book’s code to no avail.
If I got it right, the book’s source code no longer works with current versions of GHC. I tried a few things, like getting an older version of GHC and installing the dependencies through Cabal, but I always get an error when it tries to compile OpenGL (Stack gives me a similar error). Not knowing the language’s enviroment puts a handicap on what I can currently do, so I was wondering if someone has hints on what I could do to compile and run the book’s source code?
Ok, so I started following the instructions by adding these dependencies to my test project:
- GLFW >= 0.5.2.5
- OpenGL
- old-time
- stm
Then I got this message:
Error: While constructing the build plan, the following exceptions were encountered:
In the dependencies for test-0.1.0.0:
GLFW must match >=0.5.2.5, but the stack configuration has no specified version (latest matching version
is 0.5.2.5)
needed since test is a build target.
Some different approaches to resolving this:
* Recommended action: try adding the following to your extra-deps in C:\Haskell\test\stack.yaml:
- GLFW-0.5.2.5@sha256:fa54e997076a6b415c43100830e9b6ab6827c8766aef80e66d598de9b2400b93,3312
Plan construction failed.
C:\Haskell\test\package.yaml: Ignoring unrecognized field $.extra-deps
This is the full package.yaml file after adding the recommended change:
name: test
version: 0.1.0.0
github: "githubuser/test"
license: BSD3
author: "Author name here"
maintainer: "example@example.com"
copyright: "2020 Author name here"
extra-source-files:
- README.md
- ChangeLog.md
# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web
# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on GitHub at <https://github.com/githubuser/test#readme>
dependencies:
- base >= 4.7 && < 5
- OpenGL
- old-time
- stm
extra-deps:
- GLFW-0.5.2.5@sha256:fa54e997076a6b415c43100830e9b6ab6827c8766aef80e66d598de9b2400b93,3312
library:
source-dirs: src
executables:
test-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- test
tests:
test-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- test
I guess I’m setting up the project incorrectly, but I have no idea what I’m doing wrong.
You could try the HGL library that contains a Graphics.SOE module that should be compatible with the book. It compiles fine on GHC 8.8. That doesn’t require OpenGL.
Hi @jaror, thank you for the suggestion. I tried installing the latest version of HGL, but I’m getting these errors:
HGL > Graphics\HGL\Win32\WND.hs:243:37: error:
HGL > * Couldn't match type `Foreign.C.Types.CIntPtr'
HGL > with `GHC.Int.Int32'
HGL > Expected type: LONG
HGL > Actual type: LPARAM
HGL > * In the expression: x
HGL > In the first argument of `toPoint', namely `(x, y)'
HGL > In the `pt' field of a record
HGL > |
HGL > 243 | send (Button {pt = toPoint (x,y), isLeft=isLeft, isDown=isDown})
HGL > | ^
HGL >
HGL > Graphics\HGL\Win32\WND.hs:243:39: error:
HGL > * Couldn't match type `Foreign.C.Types.CIntPtr'
HGL > with `GHC.Int.Int32'
HGL > Expected type: LONG
HGL > Actual type: LPARAM
HGL > * In the expression: y
HGL > In the first argument of `toPoint', namely `(x, y)'
HGL > In the `pt' field of a record
HGL > |
HGL > 243 | send (Button {pt = toPoint (x,y), isLeft=isLeft, isDown=isDown})
HGL > | ^
HGL >
HGL > Graphics\HGL\Win32\WND.hs:248:36: error:
HGL > * Couldn't match type `Word' with `GHC.Word.Word32'
HGL > Expected type: VKey
HGL > Actual type: WPARAM
HGL > * In the first argument of `MkKey', namely `wParam'
HGL > In the `keysym' field of a record
HGL > In the first argument of `send', namely
HGL > `(Key {keysym = MkKey wParam, isDown = isDown})'
HGL > |
HGL > 248 | send (Key { keysym = MkKey wParam, isDown = isDown })
HGL > | ^^^^^^
HGL >
HGL > Graphics\HGL\Win32\WND.hs:260:41: error:
HGL > * Couldn't match type `Foreign.C.Types.CIntPtr'
HGL > with `GHC.Int.Int32'
HGL > Expected type: LONG
HGL > Actual type: LPARAM
HGL > * In the expression: x
HGL > In the first argument of `toPoint', namely `(x, y)'
HGL > In the `pt' field of a record
HGL > |
HGL > 260 | send (MouseMove { pt = toPoint (x,y) })
HGL > | ^
HGL >
HGL > Graphics\HGL\Win32\WND.hs:260:43: error:
HGL > * Couldn't match type `Foreign.C.Types.CIntPtr'
HGL > with `GHC.Int.Int32'
HGL > Expected type: LONG
HGL > Actual type: LPARAM
HGL > * In the expression: y
HGL > In the first argument of `toPoint', namely `(x, y)'
HGL > In the `pt' field of a record
HGL > |
HGL > 260 | send (MouseMove { pt = toPoint (x,y) })
HGL > | ^
HGL >
If I move back to version 3.2.2, I get this error:
Oh, that’s unfortunate. I guess the Linux parts are better maintained than the Windows part.
I have tried to update the source code to work with modern Haskell:
Can you try that?
I’ve included a cabal freeze file, so it should be reproducible. And it uses OpenGL and GLFW-b, so it should also work on Windows. But I haven’t tested that.
Hi @jaror, I was following the code in chapter 3 using your version of SOE – the window is created correctly, but the window’s context is drawn black. No matter what I try to draw in it, the context stays completely black.
As a test, I was looking for a function that would redraw the buffer with a different color, but couldn’t find it (or maybe there is a way of doing it, and my noobie-ness in Haskell prevents me from seeing it ).
I also tried disabling double buffering, but nothing changed.
I got the fixed version, but it still didn’t work. This is the code that I’m using, following the book’s example:
main :: IO ()
main = runGraphics
(do
w <- openWindow "My First Graphics Program" (800, 800)
drawInWindow w pic1
spaceClose w
)
pic1 = withColor Red (ellipse (150, 150) (300, 200))
spaceClose :: Window -> IO ()
spaceClose w = do
k <- getKey w
if k == ' ' then closeWindow w else spaceClose w
One thing that I don’t understand in this code is how the buffer is being swapped. I tried changing drawInWindow to drawInWindowNow, but nothing happened. I also tried clearWindow and other small tweaks to see if I could provoke a refresh. Do you have a small example that you know that works so I can copy it and see if it works on my side as well?
I’ve just tried your example and it works on my machine. Are you sure that you’re using the fixed version (maybe try inserting a putStrLn "test" to test it)?
What commands do you use to run it?
I have been using cabal repl in the directory that contains the haskell-school-of-expression.cabal file, then you can load in your own file with :load Myfile.hs and then you can call the main function by just typing in main or you can run one of the included programs by typing Picture.main without needing to load your own file. Picture.main should open a window with a few different shapes that you can click to bring them to the foreground. There are also Animation.main1 up to Animation.main8 which should show various animations.
Just checked the code here, I can see the line that you added.
I’m using stack since I couldn’t create a working environment using cabal. Basically, I have a package.yaml file at the root of my project and I use stack build and/or stack run to build/run the project.
I tried using cabal repl in your project folder and I got these errors:
Resolving dependencies...
cabal.exe: Could not resolve dependencies:
[__0] trying: SOE-0.1.0.0 (user goal)
[__1] next goal: base (dependency of SOE)
[__1] rejecting: base-4.14.0.0/installed-4.14.0.0, base-4.14.0.0 (constraint
from project config TODO requires ==4.13.0.0)
[__1] rejecting: base-4.13.0.0 (constraint from non-upgradeable package
requires installed instance)
[__1] rejecting: base-4.12.0.0, base-4.11.1.0, base-4.11.0.0, base-4.10.1.0,
base-4.10.0.0, base-4.9.1.0, base-4.9.0.0, base-4.8.2.0, base-4.8.1.0,
base-4.8.0.0, base-4.7.0.2, base-4.7.0.1, base-4.7.0.0, base-4.6.0.1,
base-4.6.0.0, base-4.5.1.0, base-4.5.0.0, base-4.4.1.0, base-4.4.0.0,
base-4.3.1.0, base-4.3.0.0, base-4.2.0.2, base-4.2.0.1, base-4.2.0.0,
base-4.1.0.0, base-4.0.0.0, base-3.0.3.2, base-3.0.3.1 (constraint from
project config TODO requires ==4.13.0.0)
[__1] fail (backjumping, conflict set: SOE, base)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, SOE
@jaror help is terrific, but it is evident the book has bitrot (unfortunate but unexpected — GHC does not care that much about retro compatibility and you can say similar words for the ecosystem and Windows).
Maybe there are similar publications which are readily usable?