futhask: Generate Haskell wrappers for Futhark libraries

[ bsd3, ffi-tools, library, program ] [ Propose Tags ] [ Report a vulnerability ]

Modules

[Last Documentation]

  • Backends
  • CabalGen
  • CodeGen
  • Context
  • Headers
  • Monad

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0, 0.2.0, 1.0.0
Change log ChangeLog.md
Dependencies base (>=4.7 && <5), bytestring (>=0.10 && <1), containers (>=0.6 && <1), directory (>=1.3.3 && <1.4), futhark-manifest (==1.9.0.0), futhask, raw-strings-qq (>=1.1 && <1.2), split (>=0.2.3 && <0.3), text (>=2.0.1 && <3) [details]
License BSD-3-Clause
Copyright 2020, Gusten Isfeldt
Author Gusten Isfeldt
Maintainer isfeldt@kth.se
Uploaded by GustenIsfeldt at 2026-07-08T14:40:07Z
Category FFI Tools
Source repo head: git clone https://gitlab.com/Gusten_Isfeldt/futhask.git
Distributions
Executables futhask
Downloads 435 total (11 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs not available [build log]
All reported builds failed as of 2026-07-08 [all 2 reports]

Readme for futhask-1.0.0

[back to package description]

Futhask

Futhask is a code generator that aims to create safe, Haskell friendly wrappers for Futhark libraries.

Installation

cabal install futhask

Generating code

Syntax

futhask [LIBNAME] [LIBVER] [PROGRAM.c] [PROGRAM.json] [DEST]

Example

futhark opencl --library myprogram.fut
futhask mylib 1.0 myprogram.c myprogram.json mylibrary

Using the generated code

To use local libraries, add them to the cabal.project

packages:
    DEST/*.cabal
    *.cabal

Then add them as imports in the cabal file as usual

    ...
    build-depends:
        ...
        mylib
        ...

and then

import Mylib

to get the basic interface which should be sufficient for many cases. For more granular imports, or if the access to the raw interface is desired, The following submodules are available

  • Context wrapped context instance
  • Monad Fut monad definition
  • TypeDec wrapped type declarations
  • TypeOps instances of various classes for the wrapped types
  • Types reexports TypeDec and TypeOps
  • Conversion instances of Convertible
  • EntryPoints wrapped entry points
  • Raw simply the C-API imported with the FFI
    • Context context and config functions
    • TypeDec raw type declarations
    • TypeOps type specific utility functions
    • Types reexports TypeDec and TypeOps
    • EntryPoints raw entry points
  • Unpacked
    • Types Unpacked futhark types, useful for constructing or deconstructing values
  • Native
    • Types Native type equivalents for (almost all) futhark types

Code example

Given the futhark file

type someopaque = (f32, i64)

entry foo (input:f32) : someopaque = (input, i64.f32 input)

entry bar (input:someopaque) : []f32 = replicate (input.1) (input.0)

the generated library can be used like

module FutharkUsageExample where
import Mylib

-- `foobar` composes `foo` and `bar`,
-- and converts the output array to a haskell native array
foobar :: Monad m => F32 -> m (Array F32)
foobar input = runFutT $ do
    foores <- foo input
    barres <- bar foores
    fromFuthark barres

-- `foobar'` does the same thing as `foobar` 
-- but also immediately finalizes the intermediate results
foobar' :: MonadIO m => F32 -> m (Array F32)
foobar' input = runFutT $ do
    foores <- foo input
    barres <- bar foores
    finalizeFO foores
    native_barres <- fromFuthark barres
    finalizeFO barres
    pure native_barres

Documentation

The base library contains basic documentation on the general classes and other core functions. cabal haddock can be used to obtain documentation specific to the generated library.

Generated Code

The generated code can be split in two main parts, raw and wrapped. The raw interface is simply the C-functions wrapped in the IO-monad, providing no added safety and requiring manual memory management. The wrapped interface uses newForeignPtr to introduce all Futhark pointers to the GC, and provides function types closer to those used within Futhark. In particular, unnamed tuple structures are transparent, so the arguments and return values have the same structure as in the futhark type declaration.

Primitive types

Primitive types are given aliases based on their name in futhark. For example the haskell type Float is called F32. These aliases are used in all generated type signatures.

Tuples

Unnamed tuples are recursively unpacked in all function arguments and return values in the wrapped interface, and as such are simply tuples in Haskell too. This adds a little bit of overhead at each use but can be convenient when values need to be composed or when multiple return values are desired. If unpacking is undesired, simply make a type synonym in futhark.

Opaques

Opaque values are values such as records, sums, nonprimitive arrays, and any type with an alias in the futhark file with the entry points. Unnamed types are given a name by parsing and reformatting the futhark type to a format allowed in Haskell. Since these names often end up fairly long and a little cryptic, it is recommended to name the types that are intended to be used.

Value composition and decomposition

For opaque types instances of

class (FutharkObject fo) => FutharkComposite fo where
    type Unpacked fo :: Type -> Type
    pack :: (Monad m) => Unpacked fo c -> FutT c m (fo c)
    unpack :: (Monad m) => fo c -> FutT c m (Unpacked fo c) 

can be used to compose and decompose values with their Unpacked type as an intermediate.

Haskell-native Types

In order to facilitate input and output, it is convenient to have a Haskell-native representation of the types used in the Futhark program. These are defined in the Native.Types submodule.

Unnamed types are give a name based on the futhark type, and for arrays this is just a type synonym for the native array type of the element. Named types retain their futhark name (but capitalized), and in the case of arrays this is a newtype around the native array type of the element.

All types are instances of the Element class provided by futhark-base which defines array types for them and allows the use of generic array functions like map, tabulate, etc, to be used.

Conversion

For conversion between Futhark values and Haskell native values, instances of

class Convertible fo where
    Native fo 
    toFuthark :: Monad m => Native fo -> FutT c m (fo c) 
    fromFuthark :: Monad m => fo c -> FutT c m (Native fo)

are defined. Currently instances should exist for all futhark types except those containing arrays of sum types. Note that this does not mean that all Native values can be converted to Futhark values, as only those used by the entrypoints will be defined on the futhark side. Additionally care should be taken when converting nested arrays to Futhark values, as the native array type currently does not enforce regular arrays.

Context Options

These options can be used change how the context operates. For more information see the C-API documentation.

All backends

  • TuningParameters [(String, CSize)]
  • CacheFile String Sets a cachefile for the context. Highly recommended to reduce startup times.
  • Debug Int
  • Log Int
  • Profile Int

All GPU backends

  • Device String
  • DefaultThreadBlockSize Int
  • DefaultGridSize Int
  • DefaultTileSize

OpenCL

  • Platform String
  • BuildOptions [String]

Cuda

  • NvrtcOptions [String]

Multicore

  • NumThreads Int

The Fut monad

To make the wrappers safe, and reduce clutter from explicitly passing around the context, the Fut monad is introduced. The Fut monad is an environment monad that implicitly passes the context around as necessary. Like the ST monad, the Fut monad is parameterised by a rigid type variable to prevent references to the context from escaping the monad.

To run computations, the function

mkContext :: [ContextOption] -> IO (Context, [String])

to create a context, and then run the monad with

runFutIn :: Context -> (forall c. Fut c a) -> a

Additionally

runFutWith :: [ContextOption] -> (forall c. Fut c a) -> a
runFut :: (forall c. Fut c a) -> a

are defined for convienience for cases where the context doesn't need to be reused.

The FutT transformer

For more flexibility, the FutT monad transformer can be used. For convenience the type synonyms

type Fut c = FutT c Identity
type FutIO c = FutT c IO

are defined, but entry-points and most other functions are in the polymorphic Monad m => FutT c m.

Actually these are just specialized versions of the more general transformer defined in the Futhask base library.

To run the transformer

runFutTIn :: Context -> (forall c. FutT c m a) -> m a
runFutTWith :: [ContextOption] -> (forall c. FutT c m a) -> m a
runFutT :: (forall c. FutT c m a) -> m a

For lifting

mapFutT :: (m a -> n b) -> FutT c m a -> FutT c n b
map2FutT :: (m a -> n b -> k c) -> FutT c' m a -> FutT c' n b -> FutT c' k c
pureFut :: Monad m => Fut c a -> FutT c m a
unsafeFromFutIO :: FutIO c a -> FutT c m a

Running transformer stacks

When using FutT c with other transformers in a stack the type of the function running the monad may need to be defined explicitly. In the same way as runFutT, these signatures require an explicit forall to force c to be fully polymorphic.

runMyMonad :: (forall c. MyMonad c a) -> a 

This requires the RankNTypes extension.

Memory management

All of the wrapped values have finalizers, and should eventually be garbage collected. However, GHCs GC does not know how much memory the context is using, and so collection will not always be triggered frequently enough. This is primarily an issue when the program iterates on Futhark values, without any Haskell-side allocations.

One way to deal with this is to manually manage the memory using

finalizeFO :: (MonadIO m, FutharkObject fo) => fo c -> FutT c m ()

As with any manual memory management, the programmer is responsible for ensuring that the finalized value will not be used afterwards. For cases where the object is used in more than one thread without synchronisation,

addReferenceFO :: (MonadIO m, FutharkObject fo) => fo c -> FutT c m ()

can be used. addReferenceFO increments the reference counter of the object and finalizeFO will just decrement this counter until it's 0.