hubris 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +31 -0
- data/.rvmrc +2 -0
- data/Gemfile +11 -0
- data/Haskell/Hubrify.hs +69 -0
- data/Haskell/LICENSE +22 -0
- data/Haskell/Language/Ruby/Foo.hs +20 -0
- data/Haskell/Language/Ruby/Hubris/Binding.hsc +214 -0
- data/Haskell/Language/Ruby/Hubris/GHCBuild.hs +46 -0
- data/Haskell/Language/Ruby/Hubris/Hash.hs +27 -0
- data/Haskell/Language/Ruby/Hubris/Interpolator.hs +22 -0
- data/Haskell/Language/Ruby/Hubris/LibraryBuilder.hs +181 -0
- data/Haskell/Language/Ruby/Hubris/ZCode.hs +68 -0
- data/Haskell/Language/Ruby/Hubris.hs +254 -0
- data/Haskell/Language/Ruby/Wrappers.hs +32 -0
- data/Haskell/Language/Ruby/testLib.hs +9 -0
- data/Haskell/Setup.hs +31 -0
- data/Haskell/cbits/rshim.c +46 -0
- data/Haskell/cbits/rshim.h +50 -0
- data/Haskell/hubris.cabal +53 -0
- data/INSTALL +21 -0
- data/Manifest.txt +22 -0
- data/PostInstall.txt +1 -0
- data/README.markdown +107 -0
- data/Rakefile +46 -43
- data/VERSION +1 -0
- data/doc/CommonErrors.txt +18 -0
- data/doc/CommonErrors.txt~HEAD +18 -0
- data/doc/don_feedback.txt +25 -0
- data/doc/haskell-hubris.tex +242 -0
- data/doc/new_interface.rb +74 -0
- data/doc/ruby-hubris.tex +176 -0
- data/doc/wisdom_of_ancients.txt +55 -0
- data/ext/hubris.rb +4 -0
- data/ext/stub/extconf.rb +5 -0
- data/ext/{HubrisStubLoader.c → stub/stub.c} +1 -1
- data/hubris.gemspec +31 -0
- data/lib/Makefile +181 -0
- data/lib/hubris/version.rb +3 -0
- data/lib/hubris.rb +16 -13
- data/rspec.rake +21 -0
- data/sample/Fibonacci.hs +2 -2
- data/sample/config.ru +3 -1
- data/script/ci.sh +25 -0
- data/script/console +10 -0
- data/spec/hubris_spec.rb +173 -47
- data/tasks/extconf/stub.rake +43 -0
- data/tasks/extconf.rake +13 -0
- metadata +118 -27
- data/ext/extconf.rb +0 -5
data/README.markdown
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
# Hubris
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
Hubris is a bridge between Ruby and Haskell, between love and bondage,
|
6
|
+
between slothful indolence and raw, blazing speed. Hubris will wash
|
7
|
+
your car, lie to your boss, and salvage your love life. If you are
|
8
|
+
very, very lucky, it might also let you get some functional goodness
|
9
|
+
into your ruby programs through the back door.
|
10
|
+
|
11
|
+
I probably don't have to say this, but patches are very much
|
12
|
+
welcome. If you have trouble installing it, tell me, and help me
|
13
|
+
improve the docs.
|
14
|
+
|
15
|
+
## Synopsis
|
16
|
+
|
17
|
+
The best docs, as ever, are in the tests, but as a quick precis, you
|
18
|
+
can use it a little like this:
|
19
|
+
|
20
|
+
require 'hubris' # best line ever
|
21
|
+
|
22
|
+
class Target
|
23
|
+
hubris :inline =>"triple::Int->Int; triple n = 3*n"
|
24
|
+
end
|
25
|
+
|
26
|
+
t = Target.new
|
27
|
+
puts t.triple(10)
|
28
|
+
=> 30
|
29
|
+
|
30
|
+
There are a few restrictions. All functions take one argument and
|
31
|
+
return one value: this shouldn't be a major problem because you can
|
32
|
+
pass arrays of arguments in if you need more. Hubris can currently
|
33
|
+
handle numbers, strings, basic types (like nil, true and false),
|
34
|
+
arrays and hashes. There will probably be some Ruby structures
|
35
|
+
(modules, regular expressions, etc) that won't ever be handled
|
36
|
+
natively unless someone can convince me it's a sensible thing to do.
|
37
|
+
|
38
|
+
Hubris will refuse to compile Haskell code that produces any
|
39
|
+
warnings. You can suppress this admittedly fairly strict behaviour by
|
40
|
+
passing the ":no_strict => true" flag, but in your heart of hearts
|
41
|
+
you'll know you've done the wrong thing.
|
42
|
+
|
43
|
+
There are also two other modes:
|
44
|
+
|
45
|
+
hubris :source => "MyCoolModule.hs"
|
46
|
+
|
47
|
+
which loads a source file on disk (in the same directory as your ruby),
|
48
|
+
and
|
49
|
+
|
50
|
+
hubris :module => "Data.ByteString", :packages => ["bytestring"]
|
51
|
+
|
52
|
+
which will load the Data.ByteString module which is installed on the
|
53
|
+
system. In this case, we also need to let the Haskell side know that
|
54
|
+
we'll be using the "bytestring" package, so we pass that too: You may
|
55
|
+
need to load extra packages with :inline and :source as well, and
|
56
|
+
that's supported.
|
57
|
+
|
58
|
+
|
59
|
+
## Requirements
|
60
|
+
|
61
|
+
* ghc 6.10 (to bootstrap 6.12) and cabal-install. This comes with the
|
62
|
+
Haskell Platform
|
63
|
+
* ruby 1.8.6 or higher (most heavily tested on 1.9.1)
|
64
|
+
* Linux or Mac. See
|
65
|
+
<http://www.shimweasel.com/2009/09/14/unprincipled-skulduggery-with-ghc-6-12-dylibs-on-mac-os-x>
|
66
|
+
and the following entry for more info on the Mac build.
|
67
|
+
* zsh or bash
|
68
|
+
* git
|
69
|
+
|
70
|
+
## Install
|
71
|
+
|
72
|
+
Better instructions for [Linux](http://wiki.github.com/mwotton/Hubris/installation-of-ghc-6121-on-ubuntu-910) and [Mac](http://wiki.github.com/mwotton/Hubris/installation-of-ghc-6121-on-mac-os-x)
|
73
|
+
|
74
|
+
## Contributors
|
75
|
+
|
76
|
+
* Mark Wotton
|
77
|
+
* James Britt
|
78
|
+
* Josh Price
|
79
|
+
* Tatsuhiro Ujihisa
|
80
|
+
|
81
|
+
## License
|
82
|
+
|
83
|
+
(The MIT License)
|
84
|
+
|
85
|
+
Copyright (c) 2009 Mark Wotton
|
86
|
+
|
87
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
88
|
+
a copy of this software and associated documentation files (the
|
89
|
+
'Software'), to deal in the Software without restriction, including
|
90
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
91
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
92
|
+
permit persons to whom the Software is furnished to do so, subject to
|
93
|
+
the following conditions:
|
94
|
+
|
95
|
+
The above copyright notice and this permission notice shall be
|
96
|
+
included in all copies or substantial portions of the Software.
|
97
|
+
|
98
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
99
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
100
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
101
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
102
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
103
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
104
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
105
|
+
|
106
|
+
|
107
|
+
[haskell_platform]: http://hackage.haskell.org/platform/
|
data/Rakefile
CHANGED
@@ -1,51 +1,54 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
require 'rake'
|
4
6
|
require 'fileutils'
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
#
|
13
|
-
|
14
|
-
# self.developer 'Mark Wotton', 'mwotton@gmail.com'
|
15
|
-
# self.rubyforge_name = "hubris"
|
16
|
-
# self.summary = 'tool to help build .so files from haskell code for use in Ruby via dl'
|
17
|
-
# self.post_install_message = 'PostInstall.txt'
|
18
|
-
# self.readme_file = "README.markdown"
|
19
|
-
# self.history_file = "HISTORY.markdown"
|
20
|
-
#end
|
21
|
-
|
22
|
-
#require 'newgem/tasks'
|
23
|
-
# Dir['tasks/**/*.rake'].each { |t| load t }
|
24
|
-
|
25
|
-
|
26
|
-
#file "lib/RubyMap.hs" => ["lib/RubyMap.chs"] do
|
27
|
-
# str = "c2hs -v --cppopts='-I" + Hubris::RubyHeader + "' --cpp=gcc --cppopts=-E --cppopts=-xc lib/RubyMap.chs"
|
28
|
-
# # print str
|
29
|
-
# system(str)
|
30
|
-
#end
|
31
|
-
|
32
|
-
require 'spec'
|
33
|
-
require 'spec/rake/spectask'
|
34
|
-
|
35
|
-
# desc "Run the specs under spec/"
|
36
|
-
# all_examples = Spec::Rake::SpecTask.new do |t|
|
37
|
-
# t.spec_opts = ['--options', "spec/spec.opts"]
|
38
|
-
# t.spec_files = FileList['spec/*.rb']
|
7
|
+
|
8
|
+
# require 'rake-compiler'
|
9
|
+
require 'rake/extensiontask'
|
10
|
+
# require 'rake/extensiontesttask'
|
11
|
+
|
12
|
+
|
13
|
+
# task "build:native" => [:no_extconf, :native, :build] do
|
14
|
+
# file = "pkg/stub-#{`cat VERSION`.chomp}.gem"
|
15
|
+
# mv file, "#{file.ext}-i686-linux.gem"
|
39
16
|
# end
|
40
17
|
|
41
|
-
|
18
|
+
|
19
|
+
Rake::ExtensionTask.new('stub')
|
20
|
+
|
21
|
+
# intended to be called by the gem builder
|
22
|
+
task :haskell_compile => [:compile] do
|
23
|
+
ghc_version='/usr/local/bin/ghc' # FIXME, should be able to pick
|
24
|
+
# this out from somewhere
|
25
|
+
# write the Includes file
|
26
|
+
pwd =`pwd`.strip
|
27
|
+
arch_headers = "#{RbConfig::CONFIG['rubyhdrdir']}/#{RbConfig::CONFIG['arch']}"
|
28
|
+
lib_dir = RbConfig::CONFIG['libdir']
|
29
|
+
headers = RbConfig::CONFIG['rubyhdrdir']
|
30
|
+
File.open("#{pwd}/Haskell/Language/Ruby/Hubris/Includes.hs","w") do |file|
|
31
|
+
file.write "module Language.Ruby.Hubris.Includes where
|
32
|
+
extraIncludeDirs = [\"#{headers}\", \"#{arch_headers}\"]"
|
33
|
+
end
|
34
|
+
# command="cd Haskell; cabal update; cabal install
|
35
|
+
# --extra-include-dirs=#{RbConfig::CONFIG['rubyhdrdir']}
|
36
|
+
# --extra-include-dirs=#{RbConfig::CONFIG['rubyhdrdir']}/#{RbConfig::CONFIG['arch']} --extra-lib-dirs=#{RbConfig::CONFIG['libdir']} --user --enable-shared --with-ghc=#{ghc_version}"
|
37
|
+
command="cd Haskell; cabal install --extra-include-dirs=#{arch_headers} --extra-include-dirs=#{headers} --extra-lib-dirs=#{lib_dir} --user --enable-shared --with-ghc=#{ghc_version}"
|
38
|
+
result=%x{#{command}}
|
39
|
+
raise "ERROR: ran #{command}, got #{result}" unless $?.success?
|
40
|
+
end
|
41
|
+
|
42
|
+
task :no_extconf do
|
43
|
+
$gemspec.extensions = []
|
44
|
+
end
|
45
|
+
|
46
|
+
task :default => :haskell_compile
|
42
47
|
|
43
48
|
task :clean do
|
44
49
|
FileList[File.expand_path("~/.hubris_cache/*"),
|
45
|
-
'lib*.so', 'lib/*.o'
|
46
|
-
|
47
|
-
File.delete(f)
|
48
|
-
rescue
|
49
|
-
end
|
50
|
+
'lib*.so', 'lib/*.o' ].each do |f|
|
51
|
+
File.delete(f) rescue nil
|
50
52
|
end
|
51
53
|
end
|
54
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.3
|
@@ -0,0 +1,18 @@
|
|
1
|
+
this is a quick guide to diagnosing what could be wrong.
|
2
|
+
|
3
|
+
This:
|
4
|
+
"""
|
5
|
+
/var/folders/Dz/Dz5WpFSZGUaFLA8jp8kT5E+++TM/-Tmp-/working_source.hs:7:7:
|
6
|
+
Could not find module `Foreign':
|
7
|
+
Perhaps you haven't installed the "dyn" libraries for package
|
8
|
+
`base'?
|
9
|
+
"""
|
10
|
+
|
11
|
+
indicates that GHC HEAD was not installed correctly. Run something
|
12
|
+
like "find /usr/local -iname '*dyn_hi'" to check that the GHC you are
|
13
|
+
using has all its dynamic library header files installed. If it
|
14
|
+
doesn't, you probably didn't build GHC the right way: check
|
15
|
+
http://www.shimweasel.com/2009/09/16/another-awful-hack-to-ghc-6-11
|
16
|
+
and
|
17
|
+
http://www.shimweasel.com/2009/09/14/unprincipled-skulduggery-with-ghc-6-12-dylibs-on-mac-os-x
|
18
|
+
for more info.
|
@@ -0,0 +1,18 @@
|
|
1
|
+
this is a quick guide to diagnosing what could be wrong.
|
2
|
+
|
3
|
+
This:
|
4
|
+
"""
|
5
|
+
/var/folders/Dz/Dz5WpFSZGUaFLA8jp8kT5E+++TM/-Tmp-/working_source.hs:7:7:
|
6
|
+
Could not find module `Foreign':
|
7
|
+
Perhaps you haven't installed the "dyn" libraries for package
|
8
|
+
`base'?
|
9
|
+
"""
|
10
|
+
|
11
|
+
indicates that GHC HEAD was not installed correctly. Run something
|
12
|
+
like "find /usr/local -iname '*dyn_hi'" to check that the GHC you are
|
13
|
+
using has all its dynamic library header files installed. If it
|
14
|
+
doesn't, you probably didn't build GHC the right way: check
|
15
|
+
http://www.shimweasel.com/2009/09/16/another-awful-hack-to-ghc-6-11
|
16
|
+
and
|
17
|
+
http://www.shimweasel.com/2009/09/14/unprincipled-skulduggery-with-ghc-6-12-dylibs-on-mac-os-x
|
18
|
+
for more info.
|
@@ -0,0 +1,25 @@
|
|
1
|
+
------------------------------------------------------------------------
|
2
|
+
|
3
|
+
Hubris
|
4
|
+
Ruby calling Haskell
|
5
|
+
- inline, dynamically compiled Haskell
|
6
|
+
- call precompiled stuff
|
7
|
+
|
8
|
+
Dream
|
9
|
+
Haskell to code would be Cabal package.
|
10
|
+
Ruby would be application.
|
11
|
+
|
12
|
+
FFI preprocessor:
|
13
|
+
Does Haskell foreign export
|
14
|
+
Generates marshalling boilerplate
|
15
|
+
|
16
|
+
Haskell code in Ruby
|
17
|
+
|
18
|
+
------------------------------------------------------------------------
|
19
|
+
|
20
|
+
Grammar, parsing, type-driven.
|
21
|
+
|
22
|
+
Killer demo:
|
23
|
+
- Rails site,
|
24
|
+
- super clever/ fast/ multicore Haskell code
|
25
|
+
|
@@ -0,0 +1,242 @@
|
|
1
|
+
% Local Variables:
|
2
|
+
% compile-command: "/opt/local/bin/pdflatex fp-syd.tex && open fp-syd.pdf"
|
3
|
+
% End:
|
4
|
+
|
5
|
+
\documentclass{beamer}
|
6
|
+
\usepackage{listings}
|
7
|
+
\usepackage{beamerthemesplit}
|
8
|
+
|
9
|
+
\title{Hubris}
|
10
|
+
\subtitle{A Trojan Horse for Haskell}
|
11
|
+
\author{Mark Wotton \textless mwotton@shimweasel.com\textgreater}
|
12
|
+
\date{\today}
|
13
|
+
|
14
|
+
\begin{document}
|
15
|
+
\lstset{language=Haskell}
|
16
|
+
\section{Two cultures}
|
17
|
+
\frame{\titlepage}
|
18
|
+
|
19
|
+
% \subsection
|
20
|
+
\begin{frame}
|
21
|
+
\frametitle{I \ding{170} Ruby}
|
22
|
+
\begin{itemize}
|
23
|
+
\item concise and flexible
|
24
|
+
\item Big web community, many libraries
|
25
|
+
\item Fun
|
26
|
+
\end{itemize}
|
27
|
+
\end{frame}
|
28
|
+
|
29
|
+
\begin{frame}
|
30
|
+
\frametitle{I \ding{170} Haskell}
|
31
|
+
\begin{itemize}
|
32
|
+
\item<1-> Fast (optimised native code, multicore, etc)
|
33
|
+
\item<2-> Expressive - type systems don't have to suck.
|
34
|
+
\item<3-> Provably safe at compile time
|
35
|
+
\end{itemize}
|
36
|
+
\end{frame}
|
37
|
+
|
38
|
+
|
39
|
+
\begin{frame}
|
40
|
+
\frametitle{So, why do I care?}
|
41
|
+
\begin{itemize}
|
42
|
+
\item<1-> Make it easier to slap up a quick web interface to cool
|
43
|
+
haskell code.
|
44
|
+
\item<2-> Get more web-savvy devs into the Haskell community
|
45
|
+
\end{itemize}
|
46
|
+
\end{frame}
|
47
|
+
|
48
|
+
\subsection{problems with Haskell}
|
49
|
+
\begin{frame}
|
50
|
+
\frametitle{heresies}
|
51
|
+
\setlength\parskip{0.1in}
|
52
|
+
|
53
|
+
Haskell web frameworks are still niche.
|
54
|
+
|
55
|
+
It's an engineering problem, and pretty boring.
|
56
|
+
|
57
|
+
Haskell devs aren't exactly hard to find, but they don't seem to be
|
58
|
+
web guys.
|
59
|
+
|
60
|
+
\end{frame}
|
61
|
+
|
62
|
+
\subsection{problems with Ruby}
|
63
|
+
\begin{frame}
|
64
|
+
\frametitle{lies, damn lies, benchmarks}
|
65
|
+
\center{JRuby vs GHC}
|
66
|
+
\begin{tabular}{l l l l}
|
67
|
+
Program & Time &Memory & Source Size\\ \hline
|
68
|
+
reverse-complement &5 &1 &1/4\\
|
69
|
+
regex-dna &7 &3 &1/5\\
|
70
|
+
binary-trees &8 &7 &1 \\
|
71
|
+
k-nucleotide &10 &1 &1/7 \\
|
72
|
+
pidigits &18 &18 &2 \\
|
73
|
+
n-body &26 &53 &1 \\
|
74
|
+
chameneos-redux &30 &24 &1 \\
|
75
|
+
fasta &31 &142 &1 \\
|
76
|
+
fannkuch &45 &22 &1/4 \\
|
77
|
+
spectral-norm &227 &56 &1/3 \\
|
78
|
+
mandelbrot &319 &3 &1/2\\
|
79
|
+
\end{tabular}
|
80
|
+
\end{frame}
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
\section{Hubris}
|
85
|
+
\begin{frame}
|
86
|
+
\frametitle{Peanut butter, meet chocolate}
|
87
|
+
Ruby has a heap of web frameworks, convenience libraries, well-tested
|
88
|
+
integration with javascript + CSS.
|
89
|
+
|
90
|
+
\setlength\parskip{0.25in}
|
91
|
+
|
92
|
+
Haskell is smoking fast with rock solid type safety but a relatively tiny
|
93
|
+
community
|
94
|
+
|
95
|
+
Hubris is my bridge between the two
|
96
|
+
\end{frame}
|
97
|
+
|
98
|
+
\begin{frame}
|
99
|
+
\frametitle{Again, WHY?}
|
100
|
+
There are seventy bazillion ways of talking between languages.
|
101
|
+
\begin{itemize}
|
102
|
+
\item Web services
|
103
|
+
\item text over pipes
|
104
|
+
\item Protocol buffers, Thrift
|
105
|
+
\item COM, HOC, etc (binary interfaces)
|
106
|
+
\end{itemize}
|
107
|
+
|
108
|
+
Reasons to do it this way:
|
109
|
+
\begin{itemize}
|
110
|
+
\item it's fun (for me, anyway)
|
111
|
+
\item low fuss - no explicit mapping of function interfaces
|
112
|
+
\item easy to explore a library
|
113
|
+
\item few dependencies
|
114
|
+
\end{itemize}
|
115
|
+
\end{frame}
|
116
|
+
|
117
|
+
\lstset{language=Haskell}
|
118
|
+
\subsection{Haskell example}
|
119
|
+
\begin{frame}[fragile]
|
120
|
+
\frametitle{lazy, statically typed, and pure}
|
121
|
+
Collatz.hs
|
122
|
+
\begin{lstlisting}
|
123
|
+
module Collatz where
|
124
|
+
clMax lim = maximumBy (comparing snd) (assocs arr)
|
125
|
+
where arr = listArray (1,lim)
|
126
|
+
(0:(map depth [2..]))
|
127
|
+
step x = if even x
|
128
|
+
then div x 2
|
129
|
+
else 3 * x + 1
|
130
|
+
depth x = 1 + if n <= lim
|
131
|
+
then arr ! n
|
132
|
+
else depth n
|
133
|
+
where n = step x
|
134
|
+
\end{lstlisting}
|
135
|
+
Hubrify Collatz collatz.dylib Collatz.hs
|
136
|
+
|
137
|
+
\end{frame}
|
138
|
+
|
139
|
+
\subsection{wrap it in Ruby}
|
140
|
+
\begin{frame}[fragile]
|
141
|
+
\frametitle{actually using it}
|
142
|
+
\lstset{language=Ruby}
|
143
|
+
\begin{lstlisting}
|
144
|
+
require Hubris # my favourite line
|
145
|
+
module Collatz
|
146
|
+
hubris :module => 'collatz'
|
147
|
+
end
|
148
|
+
puts Collatz.clMax(1000000)
|
149
|
+
>> 837799
|
150
|
+
\end{lstlisting}
|
151
|
+
\end{frame}
|
152
|
+
|
153
|
+
\subsection{beneath the covers}
|
154
|
+
\begin{frame}[fragile]
|
155
|
+
\frametitle{on the Haskell side}
|
156
|
+
Hubrify loads the given source files and attempts to find the
|
157
|
+
passed-in module using the GHC API.
|
158
|
+
\lstset{language=Haskell}
|
159
|
+
\begin{lstlisting}
|
160
|
+
data RValue = T_NIL | T_FIXNUM Int | ...
|
161
|
+
type Value = CULong -- imported from Ruby
|
162
|
+
class Haskellable a where
|
163
|
+
toHaskell :: RValue -> Maybe a
|
164
|
+
|
165
|
+
class Rubyable a where
|
166
|
+
toRuby :: a -> RValue
|
167
|
+
|
168
|
+
wrap :: (Haskellable a, Rubyable b) ->
|
169
|
+
(a -> b) -> (Value -> Value)
|
170
|
+
\end{lstlisting}
|
171
|
+
\end{frame}
|
172
|
+
|
173
|
+
\begin{frame}[fragile]
|
174
|
+
\frametitle{blah}
|
175
|
+
For each top level definition f, we then typecheck.
|
176
|
+
\begin{lstlisting}
|
177
|
+
(wrap f) T_NIL == T_NIL
|
178
|
+
\end{lstlisting}
|
179
|
+
if it fits, it's exportable.
|
180
|
+
|
181
|
+
create a Haskell file exporting each valid function, add a top level
|
182
|
+
manifest, and compile into a self-contained dylib.
|
183
|
+
|
184
|
+
\end{frame}
|
185
|
+
|
186
|
+
\begin{frame}
|
187
|
+
\frametitle{On the ruby side}
|
188
|
+
No Haskell-specific information at all.
|
189
|
+
|
190
|
+
We have a manifest function we need to call to find the names of
|
191
|
+
wrapped functions. (Also gives us a convenient point to initialise
|
192
|
+
the Haskell runtime)
|
193
|
+
|
194
|
+
attach all passed functions as methods on the surrounding module
|
195
|
+
|
196
|
+
\end{frame}
|
197
|
+
|
198
|
+
|
199
|
+
% \frametitle{Predictive}
|
200
|
+
\section{Making it less sucky}
|
201
|
+
\begin{frame}
|
202
|
+
\setlength\parskip{0.1in}
|
203
|
+
\frametitle{What's been done}
|
204
|
+
caching of Haskell binaries
|
205
|
+
|
206
|
+
transparent mapping - no boilerplate
|
207
|
+
|
208
|
+
separation of concerns - no compiler on server
|
209
|
+
|
210
|
+
ported to GHC
|
211
|
+
\end{frame}
|
212
|
+
|
213
|
+
\begin{frame}
|
214
|
+
\frametitle{Still to do}
|
215
|
+
one-way bridge, no callbacks to Ruby
|
216
|
+
|
217
|
+
autoconf support to find ruby libs and includes
|
218
|
+
|
219
|
+
more serious hammering to find bugs - is it legitimate to dlopen
|
220
|
+
multiple haskell dylibs?
|
221
|
+
|
222
|
+
performance testing
|
223
|
+
|
224
|
+
\end{frame}
|
225
|
+
|
226
|
+
|
227
|
+
\begin{frame}
|
228
|
+
\frametitle{Try it out!}
|
229
|
+
install GHC 6.12 release candidate
|
230
|
+
|
231
|
+
git clone git://github.com/mwotton/HaskellHubris.git
|
232
|
+
|
233
|
+
git clone git://github.com/mwotton/Hubris.git
|
234
|
+
|
235
|
+
follow the README
|
236
|
+
|
237
|
+
tell me what's missing
|
238
|
+
|
239
|
+
patches very much welcome (thanks to Josh Price, James Britt and Tatsuhiro Ujihisa)
|
240
|
+
\end{frame}
|
241
|
+
|
242
|
+
\end{document}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# IDEAS for new interface
|
2
|
+
|
3
|
+
# option 1 (implicit method name from haskell function)
|
4
|
+
class MyClass
|
5
|
+
include Hubris
|
6
|
+
def_haskell(code)
|
7
|
+
end
|
8
|
+
|
9
|
+
# option 2 (explicit method name)
|
10
|
+
class MyClass
|
11
|
+
def_haskell(method_name,code)
|
12
|
+
end
|
13
|
+
|
14
|
+
# option 3 ()
|
15
|
+
class Module
|
16
|
+
include Hubris
|
17
|
+
end
|
18
|
+
|
19
|
+
class MyClass
|
20
|
+
inline_haskell "haskell function"
|
21
|
+
end
|
22
|
+
|
23
|
+
# option 4 (more humourous)
|
24
|
+
class Module
|
25
|
+
include Hubris
|
26
|
+
end
|
27
|
+
|
28
|
+
class MyClass
|
29
|
+
hubris "haskell function"
|
30
|
+
end
|
31
|
+
|
32
|
+
#-----------------------------------------
|
33
|
+
# include at the module or package level
|
34
|
+
#=========================================
|
35
|
+
# does importing as_class make sense? no, just include the module
|
36
|
+
# when interpreting Haskell module names replace . with ::
|
37
|
+
|
38
|
+
# importing std module as a ruby module/class
|
39
|
+
hubris :package => "containers", :module => "Data.Map", :as => "Data::Map"
|
40
|
+
|
41
|
+
# importing your own module (defaults to module)
|
42
|
+
hubris :package => "mypackage", :module => "MyModule" [, :as => "MyModule"]
|
43
|
+
|
44
|
+
# implicit package handling (haskell file in my directory)
|
45
|
+
hubris :module => "haskell/shit/MyModule"
|
46
|
+
|
47
|
+
# simpler to implement option, allows more flexibility in Ruby land
|
48
|
+
module MyRubyModule
|
49
|
+
# :packages is optional, just brings in external packages.
|
50
|
+
hubris :module => "Data.Map", :packages => ["containers","foo"]
|
51
|
+
# or
|
52
|
+
hubris :source => "MyHaskellCode.hs" # , :packages => [ ... ]
|
53
|
+
# or
|
54
|
+
hubris :inline => "foo x = x * 2"
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# alternative
|
59
|
+
|
60
|
+
Hubris.import :package => "containers", :module => "Data.Map"
|
61
|
+
|
62
|
+
module MyRubyModule
|
63
|
+
include Hubris::Data::Map
|
64
|
+
end
|
65
|
+
|
66
|
+
# alternative2
|
67
|
+
|
68
|
+
module MyRubyModule
|
69
|
+
hubris :package => "containers", :module => "Data.Map"
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
6:34:58 PM Josh Price: class Module; def hubris; self.class_eval { def self.h;"hubrified!";end };end;end
|
74
|
+
6:35:10 PM Josh Price: class B;hubris;end
|