Top Banner
Perl and Haskell: Can the Twain Ever Meet? Wim Vanderbauwhede School of Computing Science, University of Glasgow, UK (tl;dr: yes)
33

Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Jul 17, 2015

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Perl and Haskell: Can the Twain Ever Meet?Wim VanderbauwhedeSchool of Computing Science, University of Glasgow, UK

(tl;dr: yes)

Page 2: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Outline

I PerlI HaskellI Calling Haskell from Perl

I CI Haskell FFII Perl Inline::CI Serialisation

I What About the Types?I The Final PictureI The Need for Proper Typing

I A Modest ProposalI ImplementationI InternalsI Example

I Conclusions

Page 3: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Perl ...

I Notorious

$_=’while(read+STDIN,$_,2048){$a=29;$b=73;$c=142;$t=255;@t=map{$_%16or$t^=$c^=($m=(11,10,116,100,11,122,20,100)[$_/16%8])&110;$t^=(72,@z=(64,72,$a^=12*($_%16 -2?0:$m&17)),$b^=$_%64?12:0,@z)[$_%8]}(16..271);if((@a=unx"C*",$_)[20]&48){$h =5;$_=unxb24,join"",@b=map{xB8,unxb8,chr($_^$a[--$h+84])}@ARGV;s/...$/1$&/;$ d=unxV,xb25,$_;$e=256|(ord$b[4])<‌<9|ord$b[3];$d=$d>‌>8^($f=$t&($d>‌>12^$d>‌>4^$d^$d/8))<‌<17,$e=$e>‌>8^($t&($g=($q=$e>‌>14&7^$e)^$q*8^$q<‌<6))<‌<9,$_=$t[$_]^(($h>‌>=8)+=$f+(~$g&$t))for@a[128..$#a]}print+x"C*",@a}’;s/x/pack+/g;eval;

I But I like Perl

Page 4: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)
Page 5: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Haskell ...

I Most empathically notdynamically typed ...

I Makes easy things hard ...I But I like Haskell

Page 6: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Haskell ...

a reputation of being esoteric

Monas Hieroglyphica,(“The Hieroglyphic Monad”),

John Dee, Antwerp 1564

Page 7: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)
Page 8: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Calling Haskell from Perl

I Why?

Page 9: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Calling Haskell from Perl

I Should be as simple as:

Page 10: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Calling Haskell from Perl

I C, the lingua francaI Haskell FFI to call Haskell from CI Perl Inline::C to call C from PerlI Serialisation

Page 11: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Code Generation

I The call to “use Call::Haskell” triggers extensive code generation:I Haskell FFI and serialisation wrappersI Corresponding C wrappers and create a C libraryI Inline::C wrapper to call the functions in the C libraryI Perl serialisation wrapper

I Compile only when Haskell source code has changed, otherwisecache

Page 12: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Serialisation

I JSON? YAML? MessagePack? No: Read and ShowI Because serialisation needs to be type-aware

I Serialisation of Perl values is done via a custom showH functionI uses Haskell type information via Data.Typeable, serialised using

show, converted to a Perl datastructure in Haskell and deserialisedusing eval.

I De-serialisation of Perl serialised values in Haskell is done viaread

I Serialisation of Haskell values is done via showI string generated by show is converted into Perl code in Haskell

I De-serialisation of Haskell result is done via a custom readHfunction

I uses eval and Perl’s autload feature

Page 13: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Linking

I FFI uses ghc as linkerI Perl requires gcc linkerI ghc does not compile dynamic libraries by defaultI Lots of fun

Page 14: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

The Final Picture

1. Perl script calls a2. Perl serialisation wrapper which calls a3. Perl Inline::C wrapper which calls a4. C FFI wrapper which calls a5. Haskell FFI wrapper which calls a6. Haskell serialisation wrapper which calls7. the original Haskell function

I All wrappers are generated and built automatically on loadingCall::Haskell

Page 15: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

What About the Types?

I The outlined approach relies on Data.Typeable, Read and Show.I Data.Typeable does not provide information on type constructors

for algebraic types.I So this approach only works for “primitive” types and containers

holding primitive types.I This is already quite a lot, but it’s not good enough.I We could add other types (e.g. Data.Map and Maybe) ad hocI However ...

Page 16: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

The Need for Proper Typing

I There is a fundamental issue with variant types.I Given following Haskell type:

data Qual a = Groot a |Klein a

I It is impossible to generate the correctly typed value for Haskellunless the value in Perl is also typed with the same information!

I So we need a type system for Perl...

Page 17: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

A Modest Proposal

I I propose to create a type system to type datastructures andfunction signatures in a dynamically typed language (Perl),

I without changing anything to the language itselfI but nevertheless with an acceptable and usable syntax.

I The types must be compatible with Haskell’s types so that it ispossible to call Haskell functions with well-typed arguments andreturn values.

I show and read the typed values in Haskell fashion.

Page 18: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Basic Functionality

I Declare the type of a typed variable:

tv :: T

I Construct a typed value from other typed and/or untyped values:

tv ′ = TC v

I Bind a typed value to a typed variable:

tv = tv ′

I Convert a typed value into an untyped value:

v u= tv

Page 19: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

A Simple Type SystemThe type system provides:

I The primitive scalar types Int, Float, String, Bool.

type TI = Inttype TF = Float

I The container types Tuple, Array and Map:

type TT = (T1,T2, ...,TN)

type TA = [T1]

type TM = {Tk ,Tv}

I A mechanism to declare and construct sum and product types:

data TS = T1 |T2 ...TN

data TP = TCP T1 ...TN

Page 20: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Implementation

I To implement this type system in Perl, we useI functions for the type constructors,I a small API of type naming, binding and construction functions.I prototypes to construct the actual types. Prototypes are functions

that return a type descriptor.I lightweight objects to represent the typed values and the type

descriptors returned by the prototypes.

I The implementation relies on two language features:I a function can query the name of its callers (caller in Perl)I data structures can be transformed into lightweight objects (bless

in Perl)

Page 21: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

newtype and typename

I To create type constructors:

TC = newtype T (Prototype T1...TN)

I If the type T is polymorphic, the type name can take parameters:

TC = newtype (T a b) (Prototype a b)

I Also used for container types

TC = newtype T (Prototype T1...TN)

I And to create an alias for an existing primitive type

T = newtype Tprim

I To declare the type name T

T = typename

Page 22: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Prototypes

I Algebraic datatypes:I Record: For product types, with optional support for named fieldsI Variant: For sum types

I Container types:I Tuple: For tuplesI Array: For listsI Map: For dictionaries

I Functions: FunctionI To construct primitive types: Scalar

Page 23: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

type and bind

I To declare a typed variable

type tv T

If the type is a polymorphic type, we can provide the typeargument:

type tv (T T1)

I To bind a typed variable to a value, we use bind, whichcorresponds to “=” in Haskell.

bind tv tv ′

If the type of a typed variable is primitive, bind can take anuntyped value as the argument:

bind tv v

Page 24: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

untype, show and read

I To return an untyped value from a typed value

v = untype tv

I Finally, read and show work as in Haskell

Page 25: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Internals: Type Names andPrototypes

I Type NamesThe typename function returns a tuple of the name of the typeand a list of the names parameters, if any. For example, given

Couldbe = typename

then the call Couldbe a b will return the tuple (Couldbe, [a,b]).I Prototypes

The prototypes take type name functions as arguments, andreturn a type descriptor, implemented as a lightweight object.Prototypes can only be called as argument to newtype, which inits turn can only be called in the body of a type constructorfunction. For example:

IntVar = typenameMkIntVar = newtype IntVar (Record String Int)

The call to Record will return and object of type Record with asattributes the type constructor name and a list of arguments tothe constructor, i.e. typenames

Page 26: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Internals: Typed Value Objects andType Construction

I Typed Value ObjectAn object with attributes Type and Value. The Type attributecontains the information returned by the typename or prototypecalls, the Value attribute is populated by a call to newtype or bind.

I Type ConstructionThe call to newtype typechecks the arguments against the typeinformation returned by the prototype, and returns a typed valueobject, with the Type field provided by the prototype.

Page 27: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Internals: Typing and Binding

I The call to type returns a typed value object with empty Valueattribute, to be filled by a call to bind.

I The call to bind takes a value, typechecks it and stores it in theValue attribute of the typed value.

I If the type is a primitive type or a container type holding primitivetypes, then the value can be untyped and is stored as-is in theValue attribute. In that case, the only checking that is performed ison the type of the container.

I Otherwise, the value must be typed and will be typechecked.

Page 28: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Internals: Typing and Binding

I For example:

type iv IntVarbind iv (MkIntVar “55” 7188 )

The call to MkIntVar will return a typed value object with as Typeattribute a Record object with typename IntVar. The typed valueiv will contain as Type attribute a tuple with as first argument thetypename IntVar. Type checking is simply a comparison of thetypenames.

I In a simpler example:

type iv’ Intbind iv’ (Int 42)

the call to (Int 42) would return a typed value object, and the bindcall would typecheck the typename from the Type attribute withthe typename from iv’

Page 29: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Function Types

I We often want to create typed functions from untyped functions.

type f Int -> Int -> Intbind f (\x y ->x+y)

I But an untyped function can still take and return typed values:

type f (Int,Int) -> Maybe Intbind f (\(x,y) -> if (y/=0) then Just x/y else Nothing)

I We allow both bare and typed values for the argument, andreturn typed values from the function.

I The call to bind creates a new function which takes typedarguments, typechecks, untypes them if required, passes themto the original function, and types the return value if required.

Page 30: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Polymorphic Binary Tree Example

I Polymorphic Binary Tree

Tree = typenameBranch = newtype (Tree a) (Variant Tree a Tree)Leaf = newtype (Tree a) Varianttype tree Tree(Int)bind tree (Branch (Branch Leaf 41 Leaf) 42 Leaf)

I Actual Perl code:

Page 31: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Typed Function Call Example

use Call::Haskell import => 'VarDeclParser( parse_vardecl )';use Types;use VarDecl;

my $tstr = String("integer :: v");

type my $fp = String => VarDecl;bind $fp, &parse_vardecl;

my $tres = $fp−>($tstr);say show $tres;my $res = untype $tres;

Page 32: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Summary

I Want proper typechecking in Perl?I https://github.com/wimvanderbauwhede/Perl-Functional-Types

I Want to call Haskell from Perl?I https://github.com/wimvanderbauwhede/Perl-Call-Haskell

Page 33: Perl and Haskell: Can the Twain Ever Meet? (tl;dr: yes)

Thank you! Questions?