haskelisp

Write Emacs module in Haskell, using Emacs 25's Dynamic Module feature http://github.com/githubuser/haskelisp#readme

Latest on Hackage:0.1.1.0

This package is not currently in any snapshots. If you're interested in using it, we recommend adding it to Stackage Nightly. Doing so will make builds more reliable, and allow stackage.org to host generated Haddocks.

GPL-3 licensed by Takenari Shinohara

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)
comments powered byDisqus