<br>I thought I&#39;d let you know that I succeeded in my experiment in calling Clean from Python. Assuming you&#39;ve already compiled a Clean dll with a function &#39;factors&#39; in it, the code ends up looking like this:
<br><br><div style="margin-left: 40px;"># Load the dll and specify the types for our function<br>&gt;&gt;&gt; from cleantypes import cdll, Int, IntArray<br>&gt;&gt;&gt; dll = cdll.LoadLibrary(&quot;test_python&quot;)<br>&gt;&gt;&gt; 
dll.factors.argtypes = [Int]<br>&gt;&gt;&gt; dll.factors.restype = IntArray<br><br># From now on we can call our function like this<br>&gt;&gt;&gt; dll.factors(60)<br>[2, 2, 3, 5]<br></div><br>I expect that the code could be improved on quite a bit, but I&#39;ll go ahead and post it here; it should be a good starting point for anyone else who wants to pursue this just in case I don&#39;t do anymore with this.
<br clear="all"><br>-- <br><br>//=][=\\<br><br><a href="mailto:tim.hochberg@ieee.org">tim.hochberg@ieee.org</a><br><br>##############################################################################################<br><br>
&quot;&quot;&quot;cleantypes<br><br>This module provides a set of types for calling functions defined in the functional<br>languge Clean using ctypes. <br><br>Note that you will need a corresponding Clean Dll to get these doctests to work
<br><br>&gt;&gt;&gt; dll = cdll.LoadLibrary(&quot;test_python&quot;)<br><br>&gt;&gt;&gt; dll.stringlen.argtypes = [String]<br>&gt;&gt;&gt; dll.stringlen.restype = Int<br><br>&gt;&gt;&gt; dll.factors.argtypes = [Int]<br>&gt;&gt;&gt; 
dll.factors.restype = IntArray<br><br>&gt;&gt;&gt; dll.arrayinverse.argtypes = [RealArray]<br>&gt;&gt;&gt; dll.arrayinverse.restype = RealArray<br><br>&gt;&gt;&gt; dll.repeatstring.argtypes = [String, Int]<br>&gt;&gt;&gt; 
dll.repeatstring.restype = String<br><br>&gt;&gt;&gt; dll.intarraysum.argtypes = [IntArray, IntArray]<br>&gt;&gt;&gt; dll.intarraysum.restype = IntArray<br><br>&gt;&gt;&gt; dll.modify.argtypes = [IntArray]<br>&gt;&gt;&gt; 
dll.modify.restype = IntArray<br><br>&gt;&gt;&gt; dll.stringlen(&quot;12345&quot;)<br>5<br>&gt;&gt;&gt; dll.factors(12)<br>[2, 2, 3]<br>&gt;&gt;&gt; dll.arrayinverse([1,2,4,8])<br>[1.0, 0.5, 0.25, 0.125]<br>&gt;&gt;&gt; dll.repeatstring
(&quot;foo&quot;, 3)<br>&#39;foofoofoo&#39;<br>&gt;&gt;&gt; dll.intarraysum([1,2,3], [4,5,6])<br>[5, 7, 9]<br><br>&quot;&quot;&quot;<br><br>from ctypes import cdll<br>from ctypes import POINTER as _POINTER, cast as _cast, sizeof as _sizeof
<br>from ctypes import c_int as Int, c_double as Real, c_char as _char<br>from ctypes import create_string_buffer as _buffer, addressof as _addressof<br><br>class _Sequence(object):<br>&nbsp;&nbsp;&nbsp; @classmethod<br>&nbsp;&nbsp;&nbsp; def _create(cls, value):
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; length = _cast(value, _POINTER(Int))[-cls.offset // _sizeof(Int)]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data = _cast(value, _POINTER(cls.kind))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shift = (cls.preamb - cls.offset) // _sizeof(cls.kind)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data[shift:shift+length]
<br>&nbsp;&nbsp;&nbsp; @classmethod<br>&nbsp;&nbsp;&nbsp; def from_param(cls, value):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if isinstance(value, cls.source):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; length = len(value)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rawdata = _buffer(_sizeof(cls.kind) * len(value) + cls.preamb)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _cast(rawdata, _POINTER(Int))[0] = length
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data = _cast(rawdata, _POINTER(cls.kind))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shift = cls.preamb // _sizeof(cls.kind)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i, x in enumerate(value):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data[i + shift] = x<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _cast(_addressof(
data.contents) + cls.offset, _POINTER(cls.kind))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif isinstance(value,&nbsp; _POINTER(cls.kind)):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return value<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise TypeError(&quot;can&#39;t convert object of type &lt;%s&gt; to type &lt;%s&gt;&quot; % 
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (type(value).__name__, cls.__name__))<br><br>class _Array(list, _Sequence):<br>&nbsp;&nbsp;&nbsp; source = list<br>&nbsp;&nbsp;&nbsp; preamb = 8<br>&nbsp;&nbsp;&nbsp; offset = 8<br>&nbsp;&nbsp;&nbsp; def __init__(self, value):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.__init__(self, self._create(value))
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>class RealArray(_Array):<br>&nbsp;&nbsp;&nbsp; kind = Real<br>&nbsp;&nbsp;&nbsp; <br>class IntArray(_Array):<br>&nbsp;&nbsp;&nbsp; kind = Int<br>&nbsp;&nbsp;&nbsp; <br>class CharArray(_Array):<br>&nbsp;&nbsp;&nbsp; kind = _char<br>&nbsp;&nbsp;&nbsp; preamb = 4<br>&nbsp;&nbsp;&nbsp; offset = 4<br>&nbsp;&nbsp;&nbsp; <br>class String(str, _Sequence):
<br>&nbsp;&nbsp;&nbsp; source = str<br>&nbsp;&nbsp;&nbsp; kind = _char<br>&nbsp;&nbsp;&nbsp; preamb = 4<br>&nbsp;&nbsp;&nbsp; offset = 0<br>&nbsp;&nbsp;&nbsp; def __new__(cls, value):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return str.__new__(cls, cls._create(value))<br><br><br>if __name__ == &quot;__main__&quot;:<br>&nbsp;&nbsp;&nbsp; import doctest, cleantypes
<br>&nbsp;&nbsp;&nbsp; doctest.testmod(cleantypes)<br><br><br><br><br>