https://wiki.haskell.org/index.php?title=HSFFIG/Examples&feed=atom&action=historyHSFFIG/Examples - Revision history2024-03-29T02:00:52ZRevision history for this page on the wikiMediaWiki 1.35.5https://wiki.haskell.org/index.php?title=HSFFIG/Examples&diff=35026&oldid=prevDimitryGolubovsky: Removed dead links to the example programs.2010-06-21T12:01:45Z<p>Removed dead links to the example programs.</p>
<table class="diff diff-contentalign-left diff-editfont-monospace" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Older revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 12:01, 21 June 2010</td>
</tr><tr>
<td colspan="2" class="diff-lineno">Line 1:</td>
<td colspan="2" class="diff-lineno">Line 1:</td>
</tr>
<tr>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>== Berkeley DB binding ==</div></td>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>== Berkeley DB binding ==</div></td>
</tr>
<tr>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td>
</tr>
<tr>
<td colspan="2" class="diff-empty"> </td>
<td class="diff-marker">+</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div>On this page, you can find code snippets demonstrating correspondence between '''C''' code and Haskell code using '''hsffig'''.</div></td>
</tr>
<tr>
<td class="diff-marker">−</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div>To test the tool, a simple example from http://www.sleepycat.com/ documentation was recoded in Haskell. The result is provided below, demonstrating Haskell code and its prototype '''C''' code fragments. The whole example files may be reached here:</div></td>
<td colspan="2" class="diff-empty"> </td>
</tr>
<tr>
<td class="diff-marker">−</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"></td>
<td colspan="2" class="diff-empty"> </td>
</tr>
<tr>
<td class="diff-marker">−</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div>* http://www.golubovsky.org/repos/hsffig/bdb/bdbtest.hs Haskell Example</div></td>
<td colspan="2" class="diff-empty"> </td>
</tr>
<tr>
<td class="diff-marker">−</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div>* http://www.golubovsky.org/repos/hsffig/bdb/example.cs C Prototype</div></td>
<td colspan="2" class="diff-empty"> </td>
</tr>
<tr>
<td class="diff-marker">−</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"></td>
<td colspan="2" class="diff-empty"> </td>
</tr>
<tr>
<td class="diff-marker">−</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div>The '''C''' code in the example is not perfect, nor is the Haskell example code. But the latter hopefully illustrates the approach to FFI programming "in Haskell almost like in '''C'''" which becomes possible by using '''hsffig'''.</div></td>
<td colspan="2" class="diff-empty"> </td>
</tr>
<tr>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td>
</tr>
<tr>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>----</div></td>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>----</div></td>
</tr>
</table>DimitryGolubovskyhttps://wiki.haskell.org/index.php?title=HSFFIG/Examples&diff=13514&oldid=prevBrettGiles: HEading level2007-06-15T22:18:18Z<p>HEading level</p>
<table class="diff diff-contentalign-left diff-editfont-monospace" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Older revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 22:18, 15 June 2007</td>
</tr><tr>
<td colspan="2" class="diff-lineno">Line 1:</td>
<td colspan="2" class="diff-lineno">Line 1:</td>
</tr>
<tr>
<td class="diff-marker">−</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div>= Berkeley DB <del class="diffchange diffchange-inline">Binding</del> =</div></td>
<td class="diff-marker">+</td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div><ins class="diffchange diffchange-inline">=</ins>= Berkeley DB <ins class="diffchange diffchange-inline">binding</ins> <ins class="diffchange diffchange-inline">=</ins>=</div></td>
</tr>
<tr>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td>
</tr>
<tr>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>To test the tool, a simple example from http://www.sleepycat.com/ documentation was recoded in Haskell. The result is provided below, demonstrating Haskell code and its prototype '''C''' code fragments. The whole example files may be reached here:</div></td>
<td class="diff-marker"> </td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>To test the tool, a simple example from http://www.sleepycat.com/ documentation was recoded in Haskell. The result is provided below, demonstrating Haskell code and its prototype '''C''' code fragments. The whole example files may be reached here:</div></td>
</tr>
</table>BrettGileshttps://wiki.haskell.org/index.php?title=HSFFIG/Examples&diff=13512&oldid=prevBrettGiles: HSFFIG Examples moved to HSFFIG/Examples2007-06-15T22:17:21Z<p>HSFFIG Examples moved to HSFFIG/Examples</p>
<table class="diff diff-contentalign-left diff-editfont-monospace" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Older revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 22:17, 15 June 2007</td>
</tr>
<!-- diff cache key wikidb_haskell:diff:wikidiff2:1.12:old-6417:rev-13512:1.10.0 -->
</table>BrettGileshttps://wiki.haskell.org/index.php?title=HSFFIG/Examples&diff=6417&oldid=prevDimitryGolubovsky: Migrated from Hawiki2006-10-03T19:15:54Z<p>Migrated from Hawiki</p>
<p><b>New page</b></p><div>= Berkeley DB Binding =<br />
<br />
To test the tool, a simple example from http://www.sleepycat.com/ documentation was recoded in Haskell. The result is provided below, demonstrating Haskell code and its prototype '''C''' code fragments. The whole example files may be reached here:<br />
<br />
* http://www.golubovsky.org/repos/hsffig/bdb/bdbtest.hs Haskell Example<br />
* http://www.golubovsky.org/repos/hsffig/bdb/example.cs C Prototype<br />
<br />
The '''C''' code in the example is not perfect, nor is the Haskell example code. But the latter hopefully illustrates the approach to FFI programming "in Haskell almost like in '''C'''" which becomes possible by using '''hsffig'''.<br />
<br />
----<br />
<br />
Beginning of the program. The '''C''' code includes all the necessary header files.<br />
<br />
<pre><br />
#include <sys/types.h><br />
<br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <string.h><br />
<br />
#include "db.h"<br />
</pre><br />
<br />
The Haskell code just imports the ''DB_H'' module auto-generated by '''hsffig''':<br />
<br />
<pre><br />
-- A Haskell implementation of the Berkeley DB example program (example.cs)<br />
<br />
{-# OPTIONS -fglasgow-exts #-}<br />
<br />
module Main where<br />
<br />
import DB_H<br />
<br />
import Control.Monad<br />
</pre><br />
<br />
----<br />
<br />
The main program begins:<br />
<br />
<pre><br />
#define DATABASE "access.db"<br />
<br />
int<br />
main()<br />
{<br />
</pre><br />
<br />
Same in Haskell:<br />
<br />
<pre><br />
main = do<br />
<br />
let dbperm = fromIntegral $ c_S_IRUSR .|. c_S_IWUSR .|. c_S_IRGRP .|. c_S_IWGRP .|. c_S_IROTH<br />
<br />
putStrLn "Test of Autogenerated BerkeleyDB Binding"<br />
</pre><br />
<br />
Here, the file access permissions constants are OR'ed to obtain the correct binary mask. Names of the constants are as imported from ''<stat.h>'', prefixed with "c_". Application of ''fromIntegral'' is needed to be able to pass this value to foreign functions.<br />
<br />
----<br />
<br />
The '''C''' program declares local variables with types. The Haskell program does not need this: all necessary "variables" are ''alloca'' 'ed as necessary when foreign functions are called.<br />
<br />
<pre><br />
DB *dbp;<br />
DBT key, data;<br />
int ret, t_ret;<br />
</pre><br />
<br />
----<br />
<br />
The first step: create the database handle.<br />
<br />
<pre><br />
/* Create the database handle and open the underlying database. */<br />
if ((ret = db_create(&dbp, NULL, 0)) != 0) {<br />
fprintf(stderr, "db_create: %s\n", db_strerror(ret));<br />
exit (1);<br />
}<br />
</pre><br />
<br />
The '''C''' ''db_create'' function requires a pointer to the database handle variable to return the result into. The variable was declared earlier as <tt>DB *dbp</tt>.<br />
<br />
<pre><br />
-- Create the database handle and open the underlying database.<br />
<br />
(ret, dbp) <- alloca $ \pdbp -> do<br />
r <- f_db_create pdbp nullPtr 0<br />
h <- peek pdbp<br />
return (r,h)<br />
<br />
putStrLn $ "DB Handle created: " ++ (show ret)<br />
</pre><br />
<br />
In Haskell however, the same may be achieved with using the ''alloca'' function. It acts similarly to '''C''' 's ''alloca'', reserving memory space upon entry into the "action" and freeing the space after the action completes. So, <tt>alloca $ \pdbp -> do</tt> allocates necessary space to fit the value ''f_db_create'' places in, being called within the "action" (whatever follows after <tt>do</tt>. The ''pdbp'' identifier will be bound to the pointer to that space. Note that it is not needed to specify the type for ''pdbp'' (this may be some clumsy identifier '''hsffig''' assigns internally). Type inference is driven by the FFI declarations autogenerated by '''hsffig''' from its input, '''C''' header file(s).<br />
<br />
The return code of ''f_db_create'' is bound to ''r''. Next, ''h'' is bound to whatever ''f_db_create'' placed into the memory at the pointer provided to it via ''pdbp'': ''peek'' retrieves the value.<br />
<br />
Returned is a tuple containing the completion code (which may be analyzed for errors), and the database handle.<br />
<br />
At this point, the Haskell program does not analyze for database opening error: this will be shown in next steps.<br />
<br />
----<br />
<br />
The next step: open the database:<br />
<br />
<pre><br />
if ((ret = dbp->open(dbp,<br />
NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {<br />
dbp->err(dbp, ret, "%s", DATABASE);<br />
goto err;<br />
}<br />
</pre><br />
<br />
Haskell code:<br />
<br />
<pre><br />
ret <- withCString "access.db" $ \dbname -> do<br />
r <- (dbp ==> X_open) dbp<br />
nullPtr<br />
dbname<br />
nullPtr<br />
(fromIntegral e_DB_BTREE)<br />
(fromIntegral c_DB_CREATE)<br />
dbperm<br />
return r<br />
<br />
putStrLn $ "Database created: " ++ (show ret)<br />
when (ret /= 0) $ do errmsg <- f_db_strerror ret >>= peekCString<br />
putStrLn $ "Error: " ++ errmsg<br />
</pre><br />
<br />
The string with database filename is passed to the action containing call to the database open function. Pointer to that function is stored in the database handle structure initialized at the previous step. So, <tt>(dbp ==> X_open)</tt> retrieves that pointer and applies the arguments: the function is called after that.<br />
<br />
Note the difference in getting the error message text. The ''dbp -> err'' function is variadic, and it is not possible to call it from Haskell code. However the ''f_db_strerror'' function is OK. Its result is marshalled back to Haskell by calling ''peekCString''.<br />
<br />
This example program does not use I/O exceptions (in real life program they are of course necessary).<br />
<br />
----<br />
<br />
The next step: write a key/data pair into the database:<br />
<br />
<pre><br />
/* Initialize key/data structures. */<br />
memset(&key, 0, sizeof(key));<br />
memset(&data, 0, sizeof(data));<br />
key.data = "fruit";<br />
key.size = sizeof("fruit");<br />
data.data = "apple";<br />
data.size = sizeof("apple");<br />
<br />
/* Store a key/data pair. */<br />
if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) == 0)<br />
printf("db: %s: key stored.\n", (char *)key.data);<br />
else {<br />
dbp->err(dbp, ret, "DB->put");<br />
goto err;<br />
}<br />
</pre><br />
<br />
The Haskell code doing the same:<br />
<br />
<pre><br />
-- Initialize key/data structures.<br />
<br />
ret <- alloca $ \dbkey -><br />
alloca $ \dbdata -><br />
withCStringLen "fruit" $ \fruit -><br />
withCStringLen "apple" $ \apple -> do<br />
(dbkey,V_data) <-- fst fruit<br />
(dbkey,V_size) <-- (fromIntegral $ snd fruit)<br />
(dbdata,V_data) <-- fst apple<br />
(dbdata,V_size) <-- (fromIntegral $ snd apple)<br />
<br />
-- Store a key/value pair.<br />
<br />
r <- (dbp ==> X_put) dbp nullPtr dbkey dbdata 0<br />
return r<br />
<br />
putStrLn $ "Data item stored: " ++ (show ret)<br />
when (ret /= 0) $ do errmsg <- f_db_strerror ret >>= peekCString<br />
putStrLn $ "Error: " ++ errmsg<br />
</pre><br />
<br />
Using ''alloca'' in Haskell is similar to opening a new '''C''' block statement (within curly brackets) and declaring local variables in it: their identifiers are visible only within the block statement. Same way here: ''dbkey'', ''dbdata'', ''fruit'', ''apple'' are not visible outside. While ''fruit'' and ''apple'' are constants (string literals) from the '''C''' function standpoint, ''dbkey'' and ''dbdata'' are true variables: '''C''' functions may change their contents; ''alloca'' allocates a whole structure on the imaginary stack. ''Dbkey'' and ''dbdata'' contain pointers to ''DBT'' 's (Berkeley DB structure types to hold keys and values) allocated by ''alloca''. So ''dbkey'' in the Haskell example is equivalent to ''&key'' in the '''C''' example, etc.<br />
<br />
----<br />
<br />
The next step: retrieve the value stored at the preceding step:<br />
<br />
<pre><br />
/* Retrieve a key/data pair. */<br />
if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0)<br />
printf("db: %s: key retrieved: data was %s.\n",<br />
(char *)key.data, (char *)data.data);<br />
else {<br />
dbp->err(dbp, ret, "DB->get");<br />
goto err;<br />
}<br />
</pre><br />
<br />
Haskell code:<br />
<br />
<pre><br />
-- Retrieve a key/value pair.<br />
<br />
(ret,<br />
ks,<br />
vs) <- alloca $ \dbkey -><br />
alloca $ \dbdata -> <br />
withCStringLen "fruit" $ \fruit -> do<br />
(dbkey,V_data) <-- fst fruit<br />
(dbkey,V_size) <-- (fromIntegral $ snd fruit)<br />
r <- (dbp ==> X_get) dbp nullPtr dbkey dbdata 0<br />
ksc <- (dbkey --> V_data) :: IO CString<br />
kss <- dbkey --> V_size<br />
if (r == 0) <br />
then do dsc <- (dbdata --> V_data) :: IO CString<br />
dss <- dbdata --> V_size<br />
ks <- peekCStringLen (ksc, fromIntegral kss)<br />
vs <- peekCStringLen (dsc ,fromIntegral dss)<br />
return (r, ks, vs)<br />
else return (r, undefined, undefined)<br />
<br />
putStrLn $ "Data item retrieved: " ++ (show ret)<br />
<br />
if (ret == 0) <br />
then putStrLn $ "Value is: " ++ vs<br />
else do errmsg <- f_db_strerror ret >>= peekCString<br />
putStrLn $ "Error: " ++ errmsg<br />
</pre><br />
<br />
The '''C''' code does not re-initialize the ''key'' structure: it was not changed by the database store operation. The Haskell code has to do this again because previous ''dbkey'' was lost. It can however be avoided if <tt>alloca $ \dbkey -></tt> was placed in the very beginning of the program: this is same as enclosing part of the '''C''' code in curly brackets and declaring local variables within.<br />
<br />
Once <tt>(dbp ==> X_get)</tt> fills in the ''DBT'' structure ''dbdata'' points at, returned string is marshalled back to Haskell by calling ''peekCStringLen''.<br />
<br />
Possible error code is processed as shown before.<br />
<br />
----<br />
<br />
The next step: delete the value stored:<br />
<br />
<pre><br />
/* Delete a key/data pair. */<br />
if ((ret = dbp->del(dbp, NULL, &key, 0)) == 0)<br />
printf("db: %s: key was deleted.\n", (char *)key.data);<br />
else {<br />
dbp->err(dbp, ret, "DB->del");<br />
goto err;<br />
}<br />
</pre><br />
<br />
Haskell code:<br />
<br />
<pre><br />
-- Delete a key/value pair.<br />
<br />
ret <- alloca $ \dbkey -><br />
withCStringLen "fruit" $ \fruit -> do<br />
(dbkey,V_data) <-- fst fruit<br />
(dbkey,V_size) <-- (fromIntegral $ snd fruit)<br />
r <- (dbp ==> X_del) dbp nullPtr dbkey 0<br />
return r<br />
<br />
putStrLn $ "Data item deleted: " ++ (show ret)<br />
when (ret /= 0) $ do errmsg <- f_db_strerror ret >>= peekCString<br />
putStrLn $ "Error: " ++ errmsg<br />
</pre><br />
<br />
Nothing really new here: <tt>(dbp ==> X_del)</tt> removes the key-value pair.<br />
<br />
----<br />
<br />
The rest of the example program retrieves the previously deleted key-value pair again, and returns with error because the pair is no longer in the database.<br />
<br />
----<br />
----<br />
[[User:DimitryGolubovsky]]</div>DimitryGolubovsky