在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):luc-tielen/souffle-haskell开源软件地址(OpenSource Url):https://github.com/luc-tielen/souffle-haskell开源编程语言(OpenSource Language):C++ 86.0%开源软件介绍(OpenSource Introduction):Souffle-haskellThis repo provides Haskell bindings for performing analyses with the Souffle Datalog language. Fun fact: this library combines both functional programming (Haskell), logic programming (Datalog / Souffle) and imperative / OO programming (C / C++). Motivating exampleLet's first write a datalog program that can check if one point is reachable from another: // We define 2 data types:
.decl edge(n: symbol, m: symbol)
.decl reachable(n: symbol, m: symbol)
// We indicate we are interested in "reachable" facts.
// NOTE: If you forget to add outputs, the souffle compiler will
// try to be smart and remove most generated code!
.output reachable
// We write down some pre-defined facts on the datalog side.
edge("a", "b").
edge("b", "c").
edge("c", "e").
edge("e", "f").
edge("c", "d").
// And we tell datalog how to check if 1 point is reachable from another.
reachable(x, y) :- edge(x, y). // base rule
reachable(x, z) :- edge(x, y), reachable(y, z). // inductive rule Now that we have the datalog code, we can generate a -- Enable some necessary extensions:
{-# LANGUAGE DeriveGeneric, DeriveAnyClass, DerivingVia, DataKinds, UndecidableInstances #-}
-- NOTE: The usage of "deriving stock", "deriving anyclass" and "deriving via" in the
-- examples below matters in order for the library to work correctly!
module Main ( main ) where
import Data.Foldable ( traverse_ )
import Control.Monad.IO.Class
import GHC.Generics
import Data.Vector
import qualified Language.Souffle.Compiled as Souffle
-- First, we define a data type representing our datalog program.
data Path = Path
-- By making Path an instance of Program, we provide Haskell with information
-- about the datalog program. It uses this to perform compile-time checks to
-- limit the amount of possible programmer errors to a minimum.
deriving Souffle.Program
via Souffle.ProgramOptions Path "path" '[Edge, Reachable]
-- Facts are represented in Haskell as simple product types,
-- Numbers map to Int32, unsigned to Word32, floats to Float,
-- symbols to Strings / Text.
data Edge = Edge String String
deriving stock (Eq, Show, Generic)
-- For simple product types, we can automatically generate the
-- marshalling/unmarshalling code of data between Haskell and datalog.
deriving anyclass Souffle.Marshal
-- By making a data type an instance of Fact, we give Haskell the
-- necessary information to bind to the datalog fact.
deriving Souffle.Fact
via Souffle.FactOptions Edge "edge" 'Souffle.Input
data Reachable = Reachable String String
deriving stock (Eq, Show, Generic)
deriving anyclass Souffle.Marshal
deriving Souffle.Fact
via Souffle.FactOptions Reachable "reachable" 'Souffle.Output
main :: IO ()
main = Souffle.runSouffle Path $ \maybeProgram -> do -- Initializes the Souffle program.
case maybeProgram of
Nothing -> liftIO $ putStrLn "Failed to load program."
Just prog -> do
Souffle.addFact prog $ Edge "d" "i" -- Adding a single fact from Haskell side
Souffle.addFacts prog [ Edge "e" "f" -- Adding multiple facts
, Edge "f" "g"
, Edge "f" "g"
, Edge "f" "h"
, Edge "g" "i"
]
Souffle.run prog -- Run the Souffle program
-- NOTE: You can change type param to fetch different relations
-- Here it requires an annotation since we directly print it
-- to stdout, but if passed to another function, it can infer
-- the correct type automatically.
-- A list of facts can also be returned here.
results :: Vector Reachable <- Souffle.getFacts prog
liftIO $ traverse_ print results
-- We can also look for a specific fact:
maybeFact <- Souffle.findFact prog $ Reachable "a" "c"
liftIO $ print $ maybeFact For more examples of how to use the top level API, you can also take a look at the tests. Getting startedThis library assumes that the Souffle include paths are properly set.
This is needed in order for the C++ code to be compiled correctly.
The easiest way to do this (that I know of) is via Nix.
Add In your package.yaml or .cabal file, make sure to add the following options (assuming package.yaml here): # ...
cxx-options:
- -D__EMBEDDED_SOUFFLE__
cxx-sources:
- /path/to/FILE.cpp # be sure to change this according to what you need!
# ... This will instruct the Souffle compiler to compile the C++ in such a way that it can be linked with other languages (including Haskell!). For an example, take a look at the configuration for the test suite of this project. If you run into C++ compilation issues when using stack, this might be because
the ghc-options:
souffle-haskell: -optcxx-std=c++17 Souffle EDSLThis package previously contained a Haskell EDSL for writing Souffle code directly in Haskell. This has now been moved to a separate package. DocumentationThe documentation for the library can be found on
Hackage.
Supported modesSouffle programs can be run in 2 ways. They can either run in interpreted mode
(using the Interpreted modeThis is probably the mode you want to start out with if you are developing a program that uses Datalog for computing certain relations. Interpreted mode offers quick development iterations (no compiling of C++ code each time you change your Datalog code). However because the Souffle code is interpreted, it can't offer the same speed as in compiled mode. If you want to use interpreted Souffle, you need to import the
Interpreter configurationThe interpreter uses CSV files to read or write facts. The configuration
allows specifiying where the fact directory is located. With the default
configuration, it will try to lookup You can also configure which souffle executable will be used. By default,
it will first look at the For more information regarding configuration, take a look at the
The separators in the CSV fact files cannot be configured at the moment.
A tab character ( Compiled modeOnce the prototyping phase of the Datalog algorithm is over, it is advised to switch over to the compiled mode. It offers much improved performance compared to the interpreted mode, at the cost of having to recompile your Datalog algorithm each time it changes. The main differences with interpreted mode are the following:
The motivating example is a complete example for the compiled mode. ContributingTLDR: Nix-based project; the Makefile contains the most commonly used commands. Long version: The project makes use of Nix to setup the development environment. Setup your environment by entering the following command: $ cachix use luctielen # Optional (improves setup time *significantly*)
$ nix-shell After this command, you can build the project: $ make configure # configures the project
$ make build # builds the haskell code
$ make lint # runs the linter
$ make hoogle # starts a local hoogle webserver IssuesFound an issue or missing a piece of functionality? Please open an issue with a description of the problem. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论