 So welcome back to Mountain West Functional Program in Comf. My name's James Britt. I'm going to talk to you about a thing called hubris. It's a bridge between Ruby and Haskell. Can you hear me okay with this? I'll try to speak up and actually talk it to the microphone instead of lean it into the laptop here. So my name's James. I've been a Rubyist since the turn of the century. You're better off just Googling my name. We can skip all that stuff. So here's what I want to cover. There's two things. Why Haskell and what's hubris? And a little back story here. First, I am not really, I don't know that much Haskell per se. Although I've been learning. And it's this interest in learning Haskell that got me involved with hubris. So a lot of what I'm going to tell you is based more on enthusiasm for certain ideas and expectations. And it occurred to me that, wow, you're going to go out there and try to talk to these people and convince them that Haskell is something they should really be interested in. But you don't actually know it that well. And I thought, well, but the talk is about hubris. So go with it. But the key thing is one point to take away from any of this, whether you care about Haskell or not. It's about feeding your head. It's about pursuing interesting ideas. One of the things I like about Mountain West RubyConf is the people who come here even while you're paid to be programmers, you'd be coding whether there was the money there or not. You're not just day coders. I believe that by and large, the majority of people here are here because they're interested in coding and hacking and learning stuff. So I hope this stuff is up your alley. So a couple of things about Haskell. How many people here have actually heard of Haskell? Golden, sweet. How many people here code all the time in Haskell? Alright, that's maybe a good thing. You can't shout at me when I tell you stuff that's wrong right away. It's a functional programming language. It's named after the mathematician Haskell. It has something of a reputation as being sort of an arcane academic language that can't actually do anything because it doesn't allow side effects or state. That's not actually true. What I like about it is that it is a purely functional programming language. It has things like type inferencing in that it has static typing, but it doesn't require an awful lot of boilerplate code to tell the machine the types of the things that you're using. It can, in many cases, infer it. Though there is a good argument for actually using explicit typing because of the safety it gives you in the code. The other thing I find interesting about it has a thing called referential transparency. It basically means you have variables that don't vary. That once you set something that's what it means. This allows interesting behavior in the code when you know that every time you call a function if you give it the exact same parameters you always get the exact same results back. And people who know from doing unit testing and mocking and so on have realized that that's sort of the ideal state, but often that's not the case and you have to do dancing to get that in your code. So a language that just does this is an extremely interesting idea to me. Now, often times when people talk about functional programming they'll toss in languages like JavaScript or Python and say, yeah, you know, you can do functional programming in Python. It's a functional programming language. Okay, they're lying to you. That's simply not true. You can do functional programming-ish kinds of things. In particular, when I believe when people refer to it this way their saying is you have higher order functions. You can pass functions around as parameters to argument, as arguments to functions. What I like to, how I think of it is behavior is a data type that you can pass around. But absent the notion of referential transparency and so on, you still run into the problems. You can't be absolutely sure about the behavior of your functions and these are key aspects of functional programming. And I got interested in Haskell probably about two years ago and I want to learn some new kind of language and I was already somewhat familiar with Lisp and was hearing more about functional programming languages, in particular languages like, well, that got grouped into that category, things such as O'Cammel, Erlang, I don't know if I had heard of Scala at the time, and Haskell. And what appealed to me about Haskell was that it seemed to be about the most hardcore of the group. My experience now with trying to learn is I think of it as the X games of programming. It is rather hardcore about what an expected view and what it wants you to do. So some other languages have fallen to that sort of broad functional programming category. They're still easy out for doing procedural or imperative programming. I wanted to put myself in a position to learn the language where that just wasn't really an option. Now the truth is in Haskell, yes, you still can do that if you want, but you're less likely to go do things that way. So another way of looking at Haskell and those kinds of languages like what people call is a fundamentalist functional programming language. In this case, they're sternly based on the lambda calculus. There's a firm mathematical basis behind it. There's a way of reasoning about your code that is rather secure. And in fact, one of the problems I had and one of the reasons that I was so interested in over this was that when I first became interested in Haskell, I couldn't find a lot of good texts to help me understand things. And my way of learning how to write programs was how I learned Ruby was I would just start writing small useful things. So I used to do an awful lot of pearl and whereas when I got interested in Ruby, things I would have knocked out in pearl I started doing in Ruby instead and I gradually built up some skills that way. But I was finding that trying to do this in Haskell was much harder because even basic stuff like reading in the command line arguments or reading in a file were not as obvious to me with my particular background. I suspect that's true of a lot of people. Now if you come from say a list background or some other kind of background, perhaps the Haskell way is perfectly obvious, but it wasn't to me. So hubris is a bridge between Ruby and Haskell and what it allows you to do is to call Haskell code from your Ruby code. The project was started by my Mark Watten. So all the good parts of what you would find out about Galhubrus and the props go to him. I got involved not too long ago primarily to help out and try to do some work on the Ruby side but I've recently become a committer on the project and the project involved both some Ruby and some Haskell and I realized that one way to learn Haskell has become a committer on a Haskell project. Some questions as to why you would actually want to use a language like Haskell in your code and primary reasons come to my mind. The code runs faster. Haskell compiles down to native code and so is going to run faster than Ruby code. The other reason why I want to just use hubris is as a means of learning Haskell. The opportunity is here that you can write applications where the parts that are kind of awkward perhaps at least initially in Haskell such as IO and stuff like that. You do all that stuff in Ruby and once you have some data you can write business logic or anything else in the Haskell part and as you become to feel more comfortable with the Haskell you can expand it. But you don't have this massively sharp learning curve just trying to get your foot and do it to learn things. The other reason is so you can impress people on Reddit and post Haskell stories. When I talk about speeding up code it would be useful to find out just how fast is fast. I had in mind a plan to give some complicated demo and it turned out to be harder than I thought to do certain things but there was an observation I got from this guy. But I was lucky enough to have stumbled across someone who had written as it happens a small bit of code that produces the Mandelbrot set both in Ruby and in Haskell. I hope I had his name right. I didn't put his name in the slides and so on so my apologies for that but his name I believe is Sabo Okrona. So I decided I was just going to swipe his code and run that for the demonstration. So first up I assume people here know what the Mandelbrot set is. Yeah okay I mean basically it's a mapping of some equation across the complex plane and it makes these posters that they sell online. And it's a very small equation it's a very small equation that you iterate over and depending on whether the result trends towards one way or the other you decide you're going to either, well in this particular case you either have something or nothing but the nicer posters have all sorts of shades depending on how fast something trends towards a particular value. So what's nice about this is it's short code but it's computationally intensive. So for certain things the speed aspect when you're coding and opening a file how much faster is it going to get if you use a different language but something like this, the speed could matter. So let me run the Ruby code. I just have this wrapped shell script that prefaces it with time so this thing just loops through and as it calculates a line it's printing out an asterisk or not and it's doing 500 iterations for each point to figure out whether it should draw something or not. So that's kind of pokey. That took what, 20 some odd seconds. So this is the Haskell version. There are a couple of ways you can run Haskell. You can typically you can compile it down or you can run it as if it were a script or you can run it inside of a repo but in this case I'm going to run some code that'll first compile it and then kick it off. So some of this time is it chugging through the compiling it and then that it comes. That's a little faster. So that's like what, three seconds? Two and a half seconds? That'll be fair. If you spend any time on Ruby Talk you'll know that there's a permanent thread about hey how can we make Ruby faster? What's the answer that you always see? I gave you a clue right there. That's right. You see. A lot of people find that unacceptable. That's not what I meant about making Ruby faster. But it's not a bad answer, right? For certain things that you want to do you want to find the language and an argument perhaps for using Haskell with Ruby is to make things faster. So it'll be fair enough to see so what does Mandelbrot and C take? Okay it takes zero seconds. And it even produces a picture. And it takes longer to load the picture than it does to generate the picture. There you go. Now mind you, I don't know that this is optimized Haskell. I'm sure that there are people, true wizards who could get every ounce of speed out of the Haskell. To me that's not really why you would pick another language if you have to do odd things to use it. You want to pick something for its comfortable benefits. So that's a demo one. There are possible reasons to use Haskell because it's faster but also because the language provides powerful abstractions which are not going to get in C. So personally I'd rather use a language that enables me to think in a particular way a reason about a problem in a particular way other than C which doesn't really suit me. And also it's not an awful lot I can say about this but yes I believe you can get parallel execution using Haskell. Which is a big win which I think would be very hard to get if you were trying to do this on your own. So in addition for Hubris being technically a bridge between two particular languages what I found is it's also a bridge between certain concepts and ways of thinking about coding. So I had mentioned that when I first was preparing my slides I wanted a really clever example and it turns out there's an interesting tutorial on the Lisp Barati site which as you might guess has a good Lisp tutorial but also has a very good Haskell introduction there. It has picnics in a robot so it's good right? And it's interesting code it's step by step it's easy to, relatively easy to follow and I thought okay so fine. I'll take this Haskell, I'll translate it to Ruby and then as an example of using Hubris I can swap out different pieces. And this turned out to be not as easy as I would have guessed but the two things I learned from this one I was getting a much better understanding of Haskell by going from existing Haskell to Ruby then if I were to try to take an existing Ruby script and try to convert that to Haskell because inevitably if I'm writing in a new language I'm not going to be writing idiomatic code but it's more useful to take idiomatic Haskell and actually to be fair this example isn't completely idiomatic he set it up in such a way that at each step you could just add code to the end of the existing code to make it easier but fundamentally small sections were pretty idiomatic Haskell trying to convert that back to Ruby was quite an eye opener. There were things in this language that were very much like Ruby and I would think that if the things that one might find appealing about Haskell are things that one would like about what makes Ruby Ruby. If you're interested in the idea of passing functions around the function composition of using blocks and iterators instead of explicit loops, Haskell has this in spades and so while I was doing this and I'm trying to port code and I'm having some difficulties doing something which seems quite trivial and straightforward and also clear in Haskell very hard in Ruby and I started thinking wow is Haskell, Matt's here? Cover your ears. Is Haskell a better Ruby? By the more diplomatic way of saying is Haskell at least an acceptable Ruby for people who like certain aspects of Ruby and a way of working could Haskell fill that role and I think yes. Mind you yes I have limited Haskell experience but so far this is one of the things that keeps pushing me to want to learn more about this language and I feel that in the time spent trying to port this code I've learned more about Ruby and I think these kinds of experiences learning a language like Haskell will in fact make you a better Rubyist. So whether you end up pursuing any long term or spending any time with it, it is a value to use a Rubyist to look at other languages in particular functional language functional programming languages to hone your Ruby skills. So I'm going to give some more code and I'm going to go show some examples of hubris and that means you will actually be looking at Haskell code and I know some of you are thinking and you're probably okay. Just remember Haskell has no side effects. Okay. If you're pure. Okay so let me get some examples here. So with that Mandelbrot as there are a couple of ways you can use hubris. The hubris project is up on GitHub. You can find it under MWatton on GitHub. I actually don't have the URL on my slides that's remarkably clever of me but I will get that information available. And the repo includes a couple of examples in there which I hope to expand but there are some basic examples of calling Haskell code using inline and you can also slurp in external Haskell files and you can also load existing Haskell library modules. So the first thing I want to show you is just doing some inline Haskell. Can you read that? Should I try to get this bigger? Change the color scheme? Do something? So this is basic Ruby script and just want to make sure that in this example it's requiring its local copy of hubris. And here's your typical definition. First you do require hubris. Always good. Then you can define a class and here's how you would add a method that was defined inline. So this here is a bit of Haskell code. This section right here, the triple colon colon int arrow int, that's a type declaration. And what this is basically saying we have a function called triple and it's of the type an int that gives us an int. And here's the actual definition. It's of n equals three times n. I think it's pretty straightforward. One of the things I like about Haskell is the way you just sort of describe what it is it's actually going to be doing. In this case it's rather straightforward. You have a variable that comes in there and it's a simple equation that you act on. A couple of things to note about this example too. Haskell uses indentation to indicate scoping and so on. So usual Haskell code, you'll see some of it will have all sorts of line breaks and stuff on one side and other stuff on the other. However, you can use curly braces and colons to get around that and this is extremely handy for these kinds of inline bits of code. But I think for anything lengthy, one of the problems with the inline for anything lengthy, this kind of definition gets kind of cumbersome. So once we have it we can create an instance of our target object and we can call that method. Yes. You know if they can't be bothered to show up. Is it big enough? All right. That was a python joke. You know it. All right. So now I can't see my command. These freaking troublemakers. I mean I'm back. So there's a little background mechanics that goes on. That's why this is wrapped in the shell script. And I'll tell you just about that when this thing finally kicks off. And I'll tell you why it's slow assuming it actually runs. What happens with Haskell while this is chugging along and I'm assuming this is the reason that it's being slow is a hubris works by loading a shared object. So if you have any inline Haskell code, the first thing it's going to do is it's going to write it out to a file. And it's going to wrap it up as a Haskell module, basically an anonymous module. So it sort of invents a name for the module name space that the actual name isn't critical. It's then going to compile that code down to a Haskell shared object. It's then going to make that available by creating a Ruby shared object. So there's a code generation behind the scenes and some C stuff and so on like that. When that's all created, that's going to produce, at least on this box, .so file. That gets required into our Ruby code and then it magically runs. I apologize for this. I haven't as last idea why this is not working much better. Yeah, I was playing with code when I should have been watching people's presentations. So that's what this code does. This is sort of a trivial example here. You define your code inline. Hubris is going to go grab this thing inline and write that to a file someplace. By default, that is var hubris and it will stick the source into the source file directory like that and stick its compiled objects into the cache. And the names don't matter. It knows how to find it. So much for that. That's handy for, I don't know, demo purposes, right? Some one-off things. If you can write a bit of code and you can get it into one or two lines that way, it'll work fine. You could also, if you want, just use like HeroDoc syntax and so on and get the line breaks in there if you want to run something larger. But you may not want to do that. And the reason for that is when Hubris runs, it was trying to do a couple of things. Not just simply make Haskell code available to Ruby side, but it's also making sure that types are correct on either side of the bridge. So if you pass in an integer from your Ruby code, you're going to have the proper integer type over on the Haskell side. And vice versa, if your Haskell code is returning some kind of type that makes sense in Ruby land, it will port it back over. And so some code that goes on that tries to wrap the code that gets executed, what I had been finding in trying to do some examples is that Hubris is a bit more fussy about the Haskell code than if you were just running it as plain Haskell code. So in cases where you could just completely skip a type declaration because it was obvious from the code and type inferencing could be used, Hubris might complain say, well, you've got to my mind that ambiguous usage of something and I can't correctly determine what this is supposed to be from one side or the other. So if you do your code inline, Hubris will automatically stick it into a module, but you have no control about the visibility of the methods you've just defined from that module. If you define it externally, and I'll show this to you, you can limit what gets exported basically from your module, so you can write a fair amount of Haskell code, but only exposed to methods that you find play nice in the context of your Ruby application. So for an example of using an external file, I decided to make a really trivial web app and made a remade application that was going to use that Mandelbrot code and just render it as a web page. This is why I accounted another interesting problem with using Hubris for various reasons of speed and so on. When you pass in a string through Hubris, it becomes a byte string on the Haskell side, not just a basic simple string. And to me, the manipulation of the code to get the correct value coming back and to make Hubris happy with the type of function I was using became more trouble than it was worth, so I cheated and I decided instead of creating a series of spaces or asterisks, I was just going to populate it with integers and then on the Ruby end, I was just going to turn that into spaces and asterisks. Fundamentally, it's the same code, so got to make this big enough. This is the controller code. Going to Hubris, I'm passing an option called no strict. When I was compiling this code through the command line it was running, but there were certain kinds of warnings that were coming out and by default when Hubris goes and takes your code, your Haskell code and tries to compile it down, it runs with strict compiler flags. And so things like warning were just causing it to boink. In production, you may prefer this. You may want to be sure that you're not going to release any code that's emitting any warnings. My purpose is I couldn't figure out how to get rid of the warnings. I didn't know whether it was something poor I wrote, whether it was just something quirky about GHC or what, so I just turned off no strict just to get this to run. And then you just point source now instead of inline, you point it to a particular file. So I tell it's off the root of my application and it's in my little Haskell directory. And when you hit the index of the web page we're going to pass in a value which by default we're going to set for 500 and that's going to be the number of iterations. And I also set some stuff up to just do some basic timing and so on. And there's some cheesy code here to just produce some kind of graphical output. The calls to count here, this is what we're going to define in our Haskell code. And that's the Haskell code. So you import a bunch of stuff. Now I mentioned that if you do inline, you get a module created for you by default. If you're calling an external file, you have to define the module. The upside of that is you can put in these parentheses the methods that you want to be visible outside this module. So when I had first done this, I had broken that it was complaining about, well, this Mandelbrot function. For whatever reason it just didn't like the type signature or the use of something, some funky thing that I could not figure out. Luckily I didn't have to. By breaking stuff up and just coming down to the one method that I care to expose I could separate that out and not worry about any quirks of hubris. So this is the code that's produced in the Mandelbrot set and I'll see if I can explain this and tell the truth at the same time. So this function here, Mandel AI, note here is no type decoration you don't need it. I mean there are times when the compiler, in this case it's GHC, the Glasgow house compiler, if it really can't figure out the type signature it will fail to build and it will yell at you. But if it can it's happy and it doesn't care. You have to be careful though it may figure out a type signature, but it may not be the type signature that you actually want and so later on there may be cases where it isn't doing what you want. I look at the writing of the type signature as something akin to a unit test. It's certainly no more worked into simply a cert. Just make sure that this is kind of a basic test. When you call me with this these are the things you're passing into me. I know that the whole notion of static typing is something of a hotspot among people in Ruby, but I think that's largely because of experience with static typing systems as found in Java, which is a whole different world. For this method though, I needed a type signature because that made you much happier. In this particular case, I'll sort it down here. This is just defining two sort of pushing properties onto the X and Y and this is pretty much the equivalent of a step function in Ruby. So it's going to iterate over X, iterate over Y. It's going to return nested arrays, as we can see in our type here, nested arrays of int and basically says, well, if the magnitude of the result of calling Mandelbrot is less than two then the stick of one in there, L stick is zero. And Mandelbrot, this thing here, it takes a function that's that, X plus Y and it takes a value. Iterate in this function here will create an infinite list of values. This is a case of lazy evaluation. This isn't really going to give you infinite anything unless you actually explicitly ask for it. And down the enter after these two exclamation points, what we're saying is we want the hundredth element. Okay? And this simply says if you pass in a value of I it's our iterator. If it's less than 100 then we don't actually want to use an iterator less than 100. So this is a case of, I've got the actual terminology, but you can specify conditions upon how things are going to operate. And in Ruby code you probably say, well, if this value was this then do that else do this and so on. I use a case statement and so on, but I actually like this Haskell syntax to just simply specify the conditions for when things are going to operate. I less than 100 then our functions equal to this expression of iterate. Otherwise just use the value I for the iterator. I have this hooked up as running under a fusion to make it a little pepier than running under web brick. And if we hit it with a web browser please come up. Okay. So that rendering with 500 iterations just under two seconds. If we wanted a higher number of iterations say 1200 you could pass that not that much longer. The Ruby version, basically another instance of this application, but in place of the Haskell code there's just the Ruby code that would be used to generate the Mandelbrot set. Much like the command line version, it's just kind of pokey slow. Really slow. 21 seconds. So there's a notable difference there. Alright, some more technical details about here. If you want to play with hubris you're going to have to have GHC 6.12, GHC Glasgow Haskell compiler. It is the current release version kind of sort of. The Haskell community has been really good about trying to make it easy to get up and running with Haskell. And so they have a bundle of things called the Haskell platform. It's sort of a batteries included packaging of Haskell and assorted libraries. That currently though ships with 6.10 and that's not going to be good enough. There is I believe to be a new release of the Haskell platform real soon now which will be with 6.12. So that will be terrific. You can however do it if you go to the GitHub Wiki for the project. I've written up some instructions on how to get everything built. There's a bit of a song and dance and getting all the dependencies set up correctly because of various quirks. You need to first install 6.10 so you can build one thing that won't build correctly under 6.12 and then you need to bring some other things in. Then they don't build but you got to download some code and then install them and make sure you always set enable shared flag. Read the website if you want to do that. I expect all this to get a lot nicer and simpler. Clearly the goal of 6.12, one of the big wins of this thing was that it can build shared objects. So no, it's kind of cutting edge now but it's certainly not going to stay that way. Two other problems. It doesn't like 64-bit operating systems. I tried installing this on my desktop machine at home and kept running into problems. This is one I discovered. This just wasn't going to work. You need an exorcist I think to get it working on Snow Leopard. Again, these are the temporary issues right now because they're a serious commitment in the Haskell community to have these things just work. It's just that it's kind of new but it's doable. So all of I've been running here, actually I've been running through a virtual machine because it was about the only reliable way to get it up and built and running. I couldn't build it on the instance of a boon-tooth that I'm running right now. So a little refresh here. Basically Haskell works, or Hubus works as it grabs the Haskell you've written whether it's online or through an external file, compiles it down to a shared object and exposes it to Ruby as a Ruby shared lib. I had taken a look to see if this thing could actually work with FFI but my understanding is that the behavior is different enough that this is a non-trivial kind of a thing. Because what's of interest of me would be to find out at one point if this could actually work with JRuby but that's a whole other project I think. There are two parts also to Hubus and when you go and install this, you actually, of course you need to install Haskell. The two parts are the Ruby Hubus which is the Ruby code that you would deal with and include in your library and then there's a Haskell part of it as well that is doing the actual compilation and so on. It does the code generation, the compilation of the code behind the scenes and so on like that. A couple of known quirks. So functions that you use that you're exposing through Hubus can only take one argument. This is not meant to be that way although it's done on purpose because Mark wants to find a more elegant solution to allowing any number of parameters in the argument but a quick way to get it working was to just settle for one and work with that and so you could do the proper wrapping of the types both ways across the bridge. The other big problem for me was that Ruby string objects gets mapped to Haskell byte strings so if you're grabbing some Haskell code that's just working with strings by default you're going to have to import a bunch of libraries converted over the byte strings and unpack some stuff and then go back and forth and that's just horrible really. And how am I on time? Any questions? Yes sir. That's a really good question. I actually don't know off top of my head. I'd be kind of surprised. I will have to try this because when I was getting problems even with simple examples I was looking through the Haskell code and seeing the cases where it's saying well if I have this, if I have that, I believe actually you can. I believe it is treated as just a value. Sort of a broad type but I am not sure but I will find out about that. I mean it would be kind of silly if you couldn't pass anything other than rather simple types. Can you call back from the Haskell slide? No. I don't think you can. Any other questions? Yes. Can you pass say functions like parts of the byte functions or can you pass a function into your Haskell code? Passing from Haskell to Ruby. I don't think so. I'd have to look but I don't know how that would be correctly marshaled across. I thought you were curious. Yeah. It would be interesting if in fact you could have that kind of behavior pass back and forth because that's sort of what makes both these languages so interesting is the notion of passing behavior around like that. Yes? Yes I have. I have a lot of experience with that. The run Haskell setup configure thing. I have scripts for that now because I've done it so often. Yes actually it is an outstanding tool. It's basically the Haskell version of Ruby gems and when it works it's golden and it tracks down dependencies. Sometimes it does not. It is not the end of the world. It's one of those things where the first time you run into problems you're cursing it all the time but after a while you have to think back to the times when you had problems with Ruby and eventually you just sort of solve them and you don't think about them in the larger picture of things. So yes most of the time, most of what you want to do is you want to use Cabal to install something. Even there you have to be careful to have your settings and to tell it to build everything with enable shared because I was running into problems where if you didn't do that across the board and then you tried to do it in one particular case, if one library was referring to another library and they weren't all on the same page about sharing there was much sadness. Yes. Any more questions? Yes. How did you need to draw your wonderful slides? I did that in Illustrator. Thank you. Thanks very much.