Transcript Haskell.NET

Haskell.NET
The Art of Avoiding Work
Oliver Hunt & Nigel Perry
University of Canterbury, New Zealand
Summary
Introduction
 Background
 Prior Art
 Challenges & Solutions
 Results
 The Future
 Questions

Introduction: What?

Implementation of Haskell 98 on
Rotor/.NET
Haskell is one of the worlds most popular
functional programming languages.
 How to compile Haskell for .NET is still a
research problem

• Can it be done “reasonably”?
• Would IL changes provide “worthwhile”
benefit:cost?
Introduction: Haskell
Well known
 Used in industry and academia
 Non-strict
 Glasgow Haskell Compiler (GHC)

Provides intermediate-level output to support
new backends
 Extends Haskell 98 – providing future
avenues of research

Introduction: Why?

Different language families are suited to
different tasks


This adds a non-strict functional language to
the languages available on .NET
To test the extent to which .NET can run
many languages.

Primarily used by object oriented imperative
languages.
Prior Art: Bridges
The functional language runs natively on
the real machine
 A software bridge is provided to the VM
 Examples:

Lambada (Haskell for JVM)
 Hugs.Net (Haskell for .NET)

Prior Art: New Languages

Designed to work on the VMs




Reduced features
Mixed compile/interpretive approaches
More OO-like type systems
Examples:

Pizza (JVM)
• Strict
• Introduced parametric polymorphism to JVM

Mondrian (.NET)
• OO-like type system
• Used a mixed compiled/interpretive approach
• Targeted at scripting applications
Haskell 98 on .NET: Challenges
Non-strict evaluation
 Functions as values
 Partial evaluation/“currying”
 Type switches

Challenge: Non-strict Evaluation

Mondrian: “External” non-strictness

Client must know
• Manual evaluation


Interpretive-like
JIT Objects: “Internal” non-strictness

Non-strictness hidden from client
• Automatic evaluation

Doesn’t support disjoint union types well
• Disjoint union types central to Haskell 98…
Haskell.NET: Non-strict Evaluation

Use “Internal” non-strictness


Primitive types




Best for interworking
Follow JIT Objects
Optimise to use single class, rather than
type/subtype combination
Auto conversion to/from values & boxed values
Function types

Use hidden nested subtype
Non-strict Evaluation (cont)

Disjoint union types



Type: abstract class
Alternatives: sub-classes
Discrimination:
• use tag fields

Resolution:
• “asX” methods rather than casting

Non-strictness
• Hidden sub-class
• Internal: evaluation hidden by tag/asX

Issues:


Casting only works for evaluated values
Not totally transparent
• But disjoint unions not “standard” OO
Non-strict types

data List a = Cons a (List a) : Nil
Challenge: Functions as values


.NET provides delegates, which are “OO function
pointers”
Unfortunately:



Relatively inefficient given the high usage in Haskell
Difficult to combine with non-strictness
Replace using a parametric function type



Provide conversions to/from delegates for inter-language
working
Extends to support partial application
Might extend to support higher-rank types (Glasgow extension)
Challenge: Partial Evaluation

Calling a function omitting arguments, to
create a new function, e.g.
Inc x = x+
 Calling (inc 3) returns a function that adds 3
to its argument


We extend our previous function type

Instance fields used to store pre-supplied
arguments
Challenge: Type Switches

Very slow in .NET
Must use a series of type checks/casts
 These checks take account of subtypes


Addressed by the addition of an explicit
tag enumerand to each type. I.e:
Effectively duplicate the hidden VM tag
 Do exact, as opposed to subtype, matching

Status

Compiler functional

But incomplete…
• Large %age of Haskell 98 language
• Smaller %age of Haskell 98 libraries
• Largely engineering, not research, left

Performance?

Primes Sieve (first 1000 primes)
• GHC Native: 0.9s
• GHC .NET: 1.5s
Future Work: Glasgow Haskell

Higher Rank Types


Passing generic functions as values
Partly supported now:
• Wrap inside interface

Higher Kind Types


E.g. allow M<X> where both M & X are variable
How to do reasonably efficiently in .NET?
• Fallback is reflection/runtime code generation…

Currently by-passed (e.g. hardwire Monad to IO)
Future Work: IL Changes?

Compared to “native” implementation:
More classes – adds VM load
 Some extra indirections – a runtime cost
 Virtual dispatch for tag checking
 Etc.


Investigate if IL changes would:
Provide Haskell a good benefit:cost
 Benefit other languages

Demo

It really does work…
Q & (maybe) A