• Stars
    star
    110
  • Rank 315,694 (Top 7 %)
  • Language
    Haskell
  • License
    BSD 3-Clause "New...
  • Created about 9 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

constraint level if statements

IfCxt

This package introduces the function:

ifCxt :: IfCxt cxt => proxy cxt -> (cxt => a) -> a -> a

This function acts like an if statement where the proxy cxt parameter is the condition. If the type checker can satisfy the cxt constraint, then the second argument cxt => a is returned; otherwise, the third argument a is returned.

Before seeing more details about how ifCxt is implemented, let's look at three examples of how to use it.

Example 1: show every type

The cxtShow function below is polymorphic over the type a. If a is an instance of Show, then cxtShow a evaluates to show a; but if a is not an instance of Show, cxtShow a evaluates to <<unshowable>>.

cxtShow :: forall a. IfCxt (Show a) => a -> String
cxtShow a = ifCxt (Proxy::Proxy (Show a))
    (show a)
    "<<unshowable>>"

In ghci:

ghci> cxtShow (1 :: Int)
"1"
ghci> cxtShow (id :: a -> a)
"<<unshowable>>"

Example 2: make your code asymptotically efficient

The nub function removes duplicate elements from lists. It can be defined as:

nub :: Eq a => [a] -> [a]
nub []     =  []
nub (x:xs) =  x : nub (filter (x/=) xs)

This function takes time O(n^2). But if we also have an Ord constraint, we can define a much more efficient version that takes time O(n log n):

nubOrd :: Ord a => [a] -> [a]
nubOrd = go . sort
    where
        go (x1:x2:xs)
            | x1==x2    =      go (x2:xs)
            | otherwise = x1 : go (x2:xs)
        go [x] = [x]
        go []  = []

Now, we can use the ifCxt function to define a version of nub that will automatically select the most efficient implementation for whatever type we happen to run it on:

cxtNub :: forall a. (Eq a, IfCxt (Ord a)) => [a] -> [a]
cxtNub = ifCxt (Proxy::Proxy (Ord a)) nubOrd nub

Example 3: make your code numerically stable

The simplest way to sum a list of numbers is:

sumSimple :: Num a => [a] -> a
sumSimple = foldl' (+) 0

This method has numerical stability issues on floating point representations. Kahan summation is a more accurate technique shown below:

sumKahan :: Num a => [a] -> a
sumKahan = snd . foldl' go (0,0)
    where
        go (c,t) i = ((t'-t)-y,t')
            where
                y = i-c
                t' = t+y

Because Kahan summation does a lot more work than simple summation, we would prefer not to run it on non-floating point types. The sumCxt function below accomplishes this:

cxtSum :: forall a. (Num a, IfCxt (Floating a)) => [a] -> a
cxtSum = ifCxt (Proxy::Proxy (Floating a)) sumKahan sumSimple

Notice that the ifCxt function is conditioning on the Floating a constraint, which isn't actually used by the sumKahan function.

How it works

The magic of the technique is in the IfCxt class:

class IfCxt (cxt :: Constraint) where
    ifCxt :: proxy cxt -> (cxt => a) -> a -> a

(Notice that making a constraint an instance of a class requires theConstraintKinds extension, and the higher order (cxt => a) parameter requires the RankNTypes extension.)

There is a "global" instance defined as:

instance {-# OVERLAPPABLE #-} IfCxt cxt where ifCxt _ t f = f

What this says is that if no more specific instance is available, then the "global" ifCxt function will be used, which always returns the f (false) parameter.

Then for every instance of every other class, we need to define an overlapping IfCxt instance that always returns the t (true) parameter. For example, for Show Int, we define:

instance {-# OVERLAPS #-} IfCxt (Show Int) where ifCxt _ t f = t

This is a lot of boilerplate, so the template haskell function mkIfCxtInstances can be used to define these instances automatically. Unfortunately, due to a bug in template haskell we cannot enumerate all the classes currently in scope. So you must manually call mkIfCxtInstances on each class you want ifCxt to work with.

More Repositories

1

HLearn

Homomorphic machine learning
Haskell
1,607
star
2

ucr-cs100

open source software construction course
C++
483
star
3

subhask

Type safe interface for working in subcategories of Hask
Haskell
413
star
4

HerbiePlugin

GHC plugin that improves Haskell code's numerical stability
Haskell
191
star
5

cmc-csci046

CMC's Data Structures and Algorithms Course Materials
TeX
54
star
6

typeparams

Lens-like interface for type level parameters; allows unboxed unboxed vectors and supercompilation
Haskell
41
star
7

cmc-csci143

big data course materials
TeX
40
star
8

cmc-csci040

Computing for the Web
HTML
37
star
9

hmm

hidden markov models in haskell
Haskell
34
star
10

datasets

A collection of publicly available datasets
Scilab
26
star
11

cmc-csci145-math166

Data Mining
TeX
23
star
12

simd

simple interface to ghc's simd vector support
Haskell
23
star
13

gitlearn

a course management system (similar to ilearn) based on git
Shell
22
star
14

parsed

a haskellified version of the classic sed unix tool
TeX
21
star
15

homoiconic

Constructs FAlgebras from typeclasses, making Haskell functions homoiconic
Haskell
18
star
16

deep-tda

TeX
17
star
17

typespeed

fork of the popular typespeed program designed for the UCR cs100 curriculum
C
16
star
18

cmc-csci181

deep learning course materials
Python
15
star
19

vector-heterogenous

Arbitrary size tuples in Haskell
Haskell
12
star
20

american-shit

primary and secondary sources documenting America's misdeads
11
star
21

geolocation

Image/text geolocation with tensorflow and the MvMF
Python
9
star
22

modulus-magnus-linguae

Python
8
star
23

ConstraintKinds

Implements common Haskell type classes using the constraint kinds pattern to allow constraints.
Haskell
7
star
24

vector-functorlazy

vectors supporting lazy fmap application; asymptotically faster in some cases
Haskell
7
star
25

metahtml

Python
6
star
26

chajda

Python
5
star
27

wiktionary_bli

TeX
4
star
28

twitter_coronavirus

Python
2
star
29

rapache

a simple webserver built with bash commands
Shell
2
star
30

pagila-hw3

Shell
1
star
31

lab-timeit2

Python
1
star
32

lambda-server

Shell
1
star
33

pagila-hw2

Shell
1
star
34

binary_search

Python
1
star
35

korean

1
star
36

wardial

Python
1
star
37

lab-goodreads

1
star
38

multiskipgram

Python
1
star
39

mediabiasfactcheck

Python
1
star
40

reddit

Python
1
star
41

fake-news

Python
1
star
42

novichenko

Python
1
star
43

twitter_postgres2

Python
1
star
44

word_ladder

Python
1
star
45

2023spring-FinTechPracticum

1
star
46

pgrollup

easy creation of rollup tables in postgresql (compute count(*) queries in constant time)
PLpgSQL
1
star
47

NovichenkoBot

Python
1
star
48

2021fintech

Jupyter Notebook
1
star
49

sorting

Python
1
star
50

2020summer

TeX
1
star
51

cv

my curriculum vitae
TeX
1
star
52

search_engine

Python
1
star
53

Classification

Haskell
1
star
54

histogram

A Haskell package for easily creating histograms
Haskell
1
star
55

haskell-lecture

Outline of material for an intro to haskell course
1
star
56

dominion

Haskell
1
star
57

pagila-midterm

PLpgSQL
1
star
58

cmc-advising

1
star
59

containers

Python
1
star
60

glowing-wookie

Haskell
1
star
61

twitter_postgres

Python
1
star
62

2021summer

1
star
63

hperfstat

haskell bindings to linux's cpu hw counters (i.e. results of `perf stat`)
1
star