Description
Write Emacs module in Haskell, using Emacs 25's Dynamic Module feature.
README.md
EXPERIMENTAL
Write Emacs module in Haskell, using Emacs 25's Dynamic Module feature.
- Only tested with linux.
 - Only tested with Stack (LTS 6.26)
 - You need to build emacs with --with-modules configuration options
 - You need to specify some ghc-options to make it work
 
Sample:
{-# LANGUAGE ForeignFunctionInterface,OverloadedStrings #-}
module Main where
import Emacs
import Foreign.C.Types
foreign export ccall "emacs_module_init" emacsModuleInit :: EmacsModule
emacsModuleInit :: EmacsModule
emacsModuleInit = defmodule "sample-module" $ do
  setVal "foo" (Symbol "bar")
  defun "square" $ \i -> do
    message "haskell squre function called"
    return $ (i*i :: Int)
main :: IO ()
main = undefined
How to use
Explain using Stack and LTS 6.26 as premise.
1. Create a new project with Stack
$ stack --resolver=lts-6.26 new mymodule
2. Change executable name to *.so and add haskelisp to the dependency
mymodule.cabal:
executable mymodule.so
  hs-source-dirs:      app
  main-is:             Main.hs
  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
  build-depends:       base
                     , mymodule
                     , haskelisp
  default-language:    Haskell2010
3. Change ghc-options and add cc-options to make shared library
mymodule.cabal:
executable mymodule.so
  ...
  cc-options:          -fPIC
  ghc-options:         -shared -dynamic -fPIC -lHSrts-ghc7.10.3
  ...
4. Modules must be GPL compatible
The shared library must include plugin_is_GPL_compatible symbol to be loaded by Emacs. Prepare a C source file and specify it with c-sources option.
$ echo 'int plugin_is_GPL_compatible;' > plugin_is_GPL_compatible.c
mymodule.cabal:
executable mymodule.so
  ...
  c-sources:           plugin_is_GPL_compatible.c
  ...
5. Write some code
Main.hs:
{-# LANGUAGE ForeignFunctionInterface,OverloadedStrings #-}
module Main where
import Emacs
import Foreign.C.Types
foreign export ccall "emacs_module_init" emacsModuleInit :: EmacsModule
emacsModuleInit :: EmacsModule
emacsModuleInit = defmodule "mymodule" $ do
  defun "mysquare" $ \i -> do
    message "haskell squre function called"
    return $ (i*i :: Int)
main :: IO ()
main = undefined
We don't need main function, but without it cause a compile error, so include a dummy one. It won't be called.
6. Build
$ stack build
7. Copy the genereated shared library under load-path
For example, if ~/.emacs.d/lisp is included in load-path:
$ cp .stack-work/install/x86_64-linux/lts-6.26/7.10.3/bin/mymodule.so ~/.emacs.d/lisp/
8. Load your shared library
(require 'mymodule)