Define Function with Constraint on List's Elements? - haskell

How can I define a function with the following signature,
f :: [Int???] -> [Int]
f xs = _ -- what I do with xs doesn't matter for the question
where a is a List of Int's
such that the first argument's inputs, i.e. list elements, must be >= 0, but <= 5 at compile-time?
In other words,
f [6] would fail to compile.

How about:
f :: [Int] -> [Int]
f = filter (\x -> x >= 0 && x <= 5)
Or do you want to enforce the bounds on the type (dependent types)?
If you want to restrict the range of the Int that is allowed you are probably better of using a smart constructor. Have a look here. The idea is that you create your own datatype and your own custom constructor:
newtype Range0_5 = Range0_5 { unRange :: Int }
makeRange0_5 :: Int -> Maybe Range0_5
makeRange0_5 x
| x >= 0 && x <= 5 = Just $ Range0_5 x
| otherwise = Nothing
If you make a smart constructor, it is important to not expose it to the user of the module. This can be done by simply not exporting the Range0_5 constructor.
However this is not a compile time check. Other languages than Haskell might be more appropriate if you really need such a feature.
Since the range is fairly small, you could also make a sum type to represent it:
data Range0_5 = Int0 | Int1 | Int2 | Int3 | Int4 | Int5

If the signature is
f :: [Int] -> [Int]
(which was the original form of the question), then it is impossible to enforce your constraint at compile time. This follows from the standard diagonalization argument of the Halting problem.
Suppose the compiler could detect that
f[g x]
should not compile. By incorporating the source code of the compiler into g, it could choose the opposite of the compiler's decision.
Following your comment on Liquid Haskell (which seems like a very interesting project), note the following:
{-# type Even = {v:Int | v mod 2 = 0} #-}
{-# foo :: n:Even -> {v:Bool | (v <=> (n mod 2 == 0))} #-}
foo :: Int -> Bool
foo n = if n^2 - 1 == (n + 1) * (n - 1) then True else foo (n - 1)
LiquidHaskell claims this function is unsafe, because, potentially foo n calls foo (n - 1). Note, however, that this will never happen: it will only be called if the relationship n2 - 1 ≠ (n + 1) (n - 1), which can never happen.
Again, this is not a criticism of the quality of LiquidHaskell, but rather just pointing out that it, too, cannot solve Halting Problem like issues.

Related

Define algebra over GF4

How to define the algebraic operations over finite field power 4 (GF4) in Haskell?
I have numbers: 0, 1, 2, 3
And the operators could look like this:
(+) x y = (x + y) `mod` 4
(*) 0 y = 0
(*) 1 y = y
(*) x 0 = 0
(*) x 1 = x
(*) 2 2 = 3
(*) 3 3 = 2
(*) 2 3 = 1
(*) 3 2 = 1
Note: (*) is not multiple mod 4!
I want to get something like this:
3 * 2 :: GF4 == 1 :: GF4
I write:
class GF4 x where
(+), (*) :: x -> x -> x
instance GF4 where
0 + 0 = 0
...
2 * 3 = 1
...
But unsuccessfully! How to write an implement of this operators by type class or type?
Like this:
data GF4 = GF4_0 | GF4_1 | GF4_2 | GF4_3
deriving (Bounded, Enum, Eq, {- Ord, maybe? -} Read, Show)
instance Num GF4 where
-- A small trick to avoid having to write all the cases by hand:
-- reuse the `Num Int` instance and use the `Enum GF4` instance to
-- convert back and forth.
-- BUT note that, though this was the original question's spec for
-- (+), this is not how addition in GF4 is usually defined. Thanks
-- to chi for pointing it out. Presumably the definition for x - y
-- below also needs to be updated; perhaps defining negate instead
-- would involve less repetition.
x + y = toEnum ((fromEnum x + fromEnum y) `mod` 4)
GF4_0 * y = 0
GF4_1 * y = y
GF4_2 * GF4_2 = GF4_3
-- etc.
-- and a couple other bookkeeping functions; see :info Num or the haddocks
x - y = toEnum ((fromEnum x - fromEnum y) `mod` 4)
fromInteger n = toEnum (fromInteger (n `mod` 4))
abs = id
signum = toEnum . signum . fromEnum
Now you can try it out in ghci:
> (3 * 2 :: GF4) == (1 :: GF4)
True
Another option that makes the Num instance less tedious is to explicitly represent it as a polynomial with mod-2 coefficients. I'll pull a silly trick I've pulled a few times before to treat Bool as mod-2 numbers (with False representing 0 and True representing 1):
instance Num Bool where
(+) = (/=)
(*) = (&&)
negate = not
abs = id
signum = id
fromInteger = odd
(An aside for the Haskell experts: if the orphan instance makes you queasy, feel free to define data Bit = O | I and write out the Num instance a bit more explicitly.)
Now we define GF4 to have two fields ("fields" in the programming sense, not the number theory sense):
data GF4 = Bool :×+ Bool deriving (Eq, {- Ord, maybe? -} Read, Show)
The ×+ is supposed to be a bit of a visual pun: we'll represent ax + b as a:×+b. Now the (corrected) Num instance looks quite a bit more ordered:
instance Num GF4 where
(a:×+b) + (a':×+b') = (a + a'):×+(b + b')
(a:×+b) * (a':×+b') = (a*a' + a*b' + b*a'):×+(a*a' + b*b')
negate = id
abs = id
signum (a:×+b) = 0:×+(a*b)
fromInteger n = 0:×+fromInteger n
x :: GF4
x = 1:×+0
Unlike the previous instance, not all inhabitants of this GF4 are available as literal numbers -- only the constant polynomials. So we define an extra value, x, to give access to the non-constant polynomials. (Or you can use the constructor directly.) Now we can try out your example in ghci; what you call 2 I call x, and what you call 3 I call x+1.
> (x+1) * x == 1
True
As #WillemVanOnsem says in the comments, GF4 should be a data type, rather than a typeclass. Despite the name, they are totally different things! A typeclass is a collection of functions which are general enough that they can have similar implementations for multiple different types; a data type is nearly the reverse, in that it defines a totally new type which the users may use as they wish.
So how do you define GF4 as a data type? The ‘simplest’ way (for one definition of ‘simplest’) is to simply define it as a wrapper around Int:
newtype GF4 = GF4 Int
(Quick note: in case you haven’t run into them before, newtypes are a special kind of data type; they are used when you want to give a new name to another type by wrapping it. See e.g. LYAH for the difference between newtypes and datas.)
Now, note that (+) and (*) are members of the Num typeclass — this makes sense, since you can implement those functions for a wide range of types — so now you can write a Num instance:
instance Num GF4 where
(+) (GF4 x) (GF4 y) = GF4 ((x + y) `mod` 4)
(*) (GF4 0) (GF4 y) = GF4 0
(*) (GF4 1) (GF4 y) = GF4 y
-- and so on and so forth
-- but Num also has some other functions; let’s implement those too
negate (GF 0) = GF 0
negate (GF 1) = (GF 3)
negate (GF 2) = GF 2
-- note that a ‘negate’ implementation automatically gives you (-) as well
abs x = x
signum x = x
-- this is an unsafe function — usually you’d avoid them, but it’s the
-- only way to implement this one
fromInteger x = if 0 <= x && x < 4 then GF (fromInteger x) else error "value out of bounds!"
Then, you can export the name of the type GF4, but not the constructor GF4 :: Int -> GF4; thus outside people can use your type, but cannot construct invalid values like GF4 30.
Yet there is a better way. Note that GF4 only has four values — so it’s totally feasible to define this as an enumeration:
data GF4 = GF0 | GF1 | GF2 | GF3
This way, you can export everything, and still have it impossible by design to construct invalid values. This is considered good practice in Haskell; for this reason alone, I would use this definition rather than the newtype one. The implementation of Num is very similar to that given above; for this reason I won’t write the whole thing out again, but you should be able to easily figure it out.
You need to specify a type in our instance declaration. E.g.
instance GF4 Int where
0 + 0 = 0
2 * 3 = 1
To use it you still need to hide (+) and (*) from Prelude:
import Prelude hiding ((*), (+))
Now you can start using your GF4 instance:
one :: Int
one = 2 * 3

Why does LiquidHaskell fail to take guard into account?

I am following the Liquid Haskell tutorial:
http://ucsd-progsys.github.io/liquidhaskell-tutorial/04-poly.html
and this example fails:
module Test2 where
import Data.Vector
import Prelude hiding (length)
vectorSum :: Vector Int -> Int
vectorSum vec = go 0 0
where
go acc i
| i < length vec = go (acc + (vec ! i)) (i + 1)
| otherwise = acc
with the following error:
Error: Liquid Type Mismatch
10 | | i < length vec = go (acc + (vec ! i)) (i + 1)
^^^^^^^^^^^^^^^^^
Inferred type
VV : {v : GHC.Types.Int | v == acc + ?b}
not a subtype of Required type
VV : {VV : GHC.Types.Int | VV < acc
&& VV >= 0}
In Context
?b : GHC.Types.Int
acc : GHC.Types.Int
The question is why? The guard (i < length vec) should ensure that (vec ! i) is safe.
This looks like a termination error. Liquid Haskell here seems to assume that acc is the termination metric of go (probably because it's the first Int argument). As such it should always be non-negative and decreasing in each iteration (hence the error message you get).
The way to fix this is providing a correct termination metric, which fulfills the above criteria. Here this would be length vec - i and the corresponding signature for go is:
{-# go :: _ -> i:_ -> _ /[length vec - i] #-}
or something along those lines.
First of all, I don't know which version of LH you were using but I just had the exact same problem. The tutorial states that
LiquidHaskell verifies vectorSum – or, to be precise, the safety of
the vector accesses vec ! i. The verification works out because
LiquidHaskell is able to automatically infer
go :: Int -> {v:Int | 0 <= v && v <= sz} -> Int
which states that the second parameter i is between 0 and the length
of vec (inclusive). LiquidHaskell uses this and the test that i < sz
to establish that i is between 0 and (vlen vec) to prove safety.
They also state that the tutorial is not in accordance with the current version of LiquidHaskell.
It seems that the (refinement-)type inference of LH has changed a bit since the tutorial was written, probably generalizing types more than before, which results in this problem.
The problem is NOT that LH doesn't figure out the guard properly. The problem is that it fails to verify the property 0 <= v.
The following checks fine with version 0.8.6.2 of LH:
{-# LIQUID "--short-names" #-}
{-# LIQUID "--no-termination" #-}
{-# LIQUID "--reflection" #-}
import Prelude hiding (length)
import Data.Vector
{-# go' :: v:Vector Int -> Int -> {i:Int | i>=0 } ->Int #-}
go' :: Vector Int -> Int -> Int -> Int
go' vec acc i
| i < sz = go' vec (acc + (vec ! i)) (i + 1)
| otherwise = acc
where sz = length vec
vecSum :: Vector Int -> Int
vecSum vec = go' vec 0 0
It seems that LH infers thas go is a function in its own right and might be called with an integer smaller than 0 (which it obviously isn't).
I am still playing with that example to convince LH of this fact. If anybody had more success on this please leave a comment.
EDIT:
I found the following paragraph in the same tutorial; It seems that this might have changed:
At the call loop 0 n 0 body the parameters lo and hi are instantiated
with 0 and n respectively, which, by the way is where the inference
engine deduces non-negativity.

Show basic arithmetic functions as string

for a homework assignment, a subtask is to make the arithmetic functions (+), (-), (*) and div showable.
We're solved the rest of the assignment, but we're stuck here. Right now we're using the solution to this question here to distinguish between the operations:
showOp op = case op 3 3 of
6 -> "plus"
0 -> "minus"
9 -> "times"
1 -> "divide"
_ -> "undefined"
However, this strikes me as kind of ugly as things like showOp (\a b -> a * 3 - y) yield "plus".
Is there any way to better distinguish between the operators?
We are using winhugs atm with the appropriate switches -98 +o in order to be able to use the needed extensions.
Edit:
As requested, the actual assignment has to do with Arrays (specifically Array Int (Int -> Int -> Int)). It has to do with generating arrays of operators that fulfill certain conditions.
The assignment states:
Make the data type Array Int (Int->Int-Int) an Instance of Show. The arithmetic operations from the previous exercises should be represented as "plus", "minus", "times" and "div".
thx for any help in advance
Use induction :)
{-# LANGUAGE FlexibleInstances #-}
instance Eq (Int-> Int -> Int) where
f == g = induce f g where
base = 1
n = 2
induce f g = and [f 1 n' == g 1 n' | n' <- [base, n, n+1]]
instance Show (Int-> Int -> Int) where
show a = showOp a where
showOp op = case lookup op ops of
Just a -> a
otherwise -> "undefined"
ops = [((+),"plus")
,((-),"minus")
,((*),"times")
,(div,"divide")]
Output:
*Main> (\a b -> a * 3 - b) :: (Int->Int->Int)
undefined

Summing a large list of numbers is too slow

Task: "Sum the first 15,000,000 even numbers."
Haskell:
nats = [1..] :: [Int]
evens = filter even nats :: [Int]
MySum:: Int
MySum= sum $ take 15000000 evens
...but MySum takes ages. More precisely, about 10-20 times slower than C/C++.
Many times I've found, that a Haskell solution coded naturally is something like 10 times slower than C. I expected that GHC was a very neatly optimizing compiler and task such this don't seem that tough.
So, one would expect something like 1.5-2x slower than C. Where is the problem?
Can this be solved better?
This is the C code I'm comparing it with:
long long sum = 0;
int n = 0, i = 1;
for (;;) {
if (i % 2 == 0) {
sum += i;
n++;
}
if (n == 15000000)
break;
i++;
}
Edit 1: I really know, that it can be computed in O(1). Please, resist.
Edit 2: I really know, that evens are [2,4..] but the function even could be something else O(1) and need to be implemented as a function.
Lists are not loops
So don't be surprised if using lists as a loop replacement, you get slower code if the loop body is small.
nats = [1..] :: [Int]
evens = filter even nats :: [Int]
dumbSum :: Int
dumbSum = sum $ take 15000000 evens
sum is not a "good consumer", so GHC is not (yet) able to eliminate the intermediate lists completely.
If you compile with optimisations (and don't export nat), GHC is smart enough to fuse the filter with the enumeration,
Rec {
Main.main_go [Occ=LoopBreaker]
:: GHC.Prim.Int# -> GHC.Prim.Int# -> [GHC.Types.Int]
[GblId, Arity=1, Caf=NoCafRefs, Str=DmdType L]
Main.main_go =
\ (x_aV2 :: GHC.Prim.Int#) ->
let {
r_au7 :: GHC.Prim.Int# -> [GHC.Types.Int]
[LclId, Str=DmdType]
r_au7 =
case x_aV2 of wild_Xl {
__DEFAULT -> Main.main_go (GHC.Prim.+# wild_Xl 1);
9223372036854775807 -> n_r1RR
} } in
case GHC.Prim.remInt# x_aV2 2 of _ {
__DEFAULT -> r_au7;
0 ->
let {
wild_atm :: GHC.Types.Int
[LclId, Str=DmdType m]
wild_atm = GHC.Types.I# x_aV2 } in
let {
lvl_s1Rp :: [GHC.Types.Int]
[LclId]
lvl_s1Rp =
GHC.Types.:
# GHC.Types.Int wild_atm (GHC.Types.[] # GHC.Types.Int) } in
\ (m_aUL :: GHC.Prim.Int#) ->
case GHC.Prim.<=# m_aUL 1 of _ {
GHC.Types.False ->
GHC.Types.: # GHC.Types.Int wild_atm (r_au7 (GHC.Prim.-# m_aUL 1));
GHC.Types.True -> lvl_s1Rp
}
}
end Rec }
but that's as far as GHC's fusion takes it. You are left with boxing Ints and constructing list cells. If you give it a loop, like you give it to the C compiler,
module Main where
import Data.Bits
main :: IO ()
main = print dumbSum
dumbSum :: Int
dumbSum = go 0 0 1
where
go :: Int -> Int -> Int -> Int
go sm ct n
| ct >= 15000000 = sm
| n .&. 1 == 0 = go (sm + n) (ct+1) (n+1)
| otherwise = go sm ct (n+1)
you get the approximate relation of running times between the C and the Haskell version you expected.
This sort of algorithm is not what GHC has been taught to optimise well, there are bigger fish to fry elsewhere before the limited manpower is put into these optimisations.
The problem why list fusion can't work here is actually rather subtle. Say we define the right RULE to fuse the list away:
import GHC.Base
sum2 :: Num a => [a] -> a
sum2 = sum
{-# NOINLINE [1] sum2 #-}
{-# RULES "sum" forall (f :: forall b. (a->b->b)->b->b).
sum2 (build f) = f (+) 0 #-}
(The short explanation is that we define sum2 as an alias of sum, which we forbid GHC to inline early, so the RULE has a chance to fire before sum2 gets eliminated. Then we look for sum2 directly next to the list-builder build (see definition) and replace it by direct arithmetic.)
This has mixed success, as it yields the following Core:
Main.$wgo =
\ (w_s1T4 :: GHC.Prim.Int#) ->
case GHC.Prim.remInt# w_s1T4 2 of _ {
__DEFAULT ->
case w_s1T4 of wild_Xg {
__DEFAULT -> Main.$wgo (GHC.Prim.+# wild_Xg 1);
15000000 -> 0
};
0 ->
case w_s1T4 of wild_Xg {
__DEFAULT ->
case Main.$wgo (GHC.Prim.+# wild_Xg 1) of ww_s1T7 { __DEFAULT ->
GHC.Prim.+# wild_Xg ww_s1T7
};
15000000 -> 15000000
}
}
Which is nice, completely fused code - with the sole problem that we have a call to $wgo in a non-tail-call position. This means that we aren't looking at a loop, but actually at a deeply recursive function, with predictable program results:
Stack space overflow: current size 8388608 bytes.
The root problem here is that the Prelude's list fusion can only fuse right folds, and computing the sum as a right fold directly causes the excessive stack consumption.
The obvious fix would be to use a fusion framework that can actually deal with left folds, such as Duncan's stream-fusion package, which actually implements sum fusion.
Another solution would be to hack around it - and implement the left fold using a right fold:
main = print $ foldr (\x c -> c . (+x)) id [2,4..15000000] 0
This actually produces close-to-perfect code with current versions of GHC. On the other hand, this is generally not a good idea as it relies on GHC being smart enough to eliminate the partially applied functions. Already adding a filter into the chain will break that particular optimization.
Sum first 15,000,000 even numbers:
{-# LANGUAGE BangPatterns #-}
g :: Integer -- 15000000*15000001 = 225000015000000
g = go 1 0 0
where
go i !a c | c == 15000000 = a
go i !a c | even i = go (i+1) (a+i) (c+1)
go i !a c = go (i+1) a c
ought to be the fastest.
If you want to be sure to traverse the list only once, you can write the traversal explicitly:
nats = [1..] :: [Int]
requiredOfX :: Int -> Bool -- this way you can write a different requirement
requiredOfX x = even x
dumbSum :: Int
dumbSum = dumbSum' 0 0 nats
where dumbSum' acc 15000000 _ = acc
dumbSum' acc count (x:xs)
| requiredOfX x = dumbSum' (acc + x) (count + 1) xs
| otherwise = dumbSum' acc (count + 1) xs
First, you can be clever as young Gauss was and compute the sum in O(1).
Fun stuff aside, your Haskell solution uses lists. I'm quite sure your C/C++ solution doesn't. (Haskell lists are very easy to use so one is tempted to use them even in cases where it might not be appropriate.) Try benchmarking this:
sumBy2 :: Integer -> Integer
sumBy2 = f 0
where
f result n | n <= 1 = result
| otherwise = f (n + result) (n - 2)
Compile it using GHC with -O2 argument. This function is tail-recursive so compiler can implement it very efficiently.
Update: If you want it using even function, it's possible:
sumBy2 :: Integer -> Integer
sumBy2 = f 0
where
f result n | n <= 0 = result
| even n = f (n + result) (n - 1)
| otherwise = f result (n - 1)
You can also easily make the filtering function a parameter:
sumFilter :: (Integral a) => (a -> Bool) -> a -> a
sumFilter filtfn = f 0
where
f result n | n <= 0 = result
| filtfn n = f (n + result) (n - 1)
| otherwise = f result (n - 1)
Strict version works much faster:
foldl' (+) 0 $ take 15000000 [2, 4..]
Another thing to note is that nats and evens are so-called Constant Applicative Forms, or CAFs for short. Basically, those correspond to top-level definitions without any arguments. CAFs are a bit of an odd duck, for instance being the reason for the Dreaded Monomorphism Restriction; I'm not sure the language definition even allows CAFs to be inlined.
In my mental model of how Haskell executes, by the time dumbSum returns a value, evens will be evaluated to look something like 2:4: ... : 30000000 : <thunk> and nats to 1:2: ... : 30000000 : <thunk>, where the <thunk>s represent something that's not been looked at yet. If my understanding is correct, these allocations of : do have to happen and can't be optimized away.
So one way of speeding things up without altering your code too much would be to simply write:
dumbSum :: Int
dumbSum = sum . take 15000000 . filter even $ [1..]
or
dumbSum = sum $ take 15000000 evens where
nats = [1..]
evens = filter even nats
On my machine, compiled with -O2, that alone seems to result in a roughly 30% speedup.
I'm no GHC connaisseur (I've never even profiled a Haskell program!), so I could be wildly off the mark, though.

Strange pattern matching with functions instancing Show

So I'm writing a program which returns a procedure for some given arithmetic problem, so I wanted to instance a couple of functions to Show so that I can print the same expression I evaluate when I test. The trouble is that the given code matches (-) to the first line when it should fall to the second.
{-# OPTIONS_GHC -XFlexibleInstances #-}
instance Show (t -> t-> t) where
show (+) = "plus"
show (-) = "minus"
main = print [(+),(-)]
returns
[plus,plus]
Am I just committing a mortal sin printing functions in the first place or is there some way I can get it to match properly?
edit:I realise I am getting the following warning:
Warning: Pattern match(es) are overlapped
In the definition of `show': show - = ...
I still don't know why it overlaps, or how to stop it.
As sepp2k and MtnViewMark said, you can't pattern match on the value of identifiers, only on constructors and, in some cases, implicit equality checks. So, your instance is binding any argument to the identifier, in the process shadowing the external definition of (+). Unfortunately, this means that what you're trying to do won't and can't ever work.
A typical solution to what you want to accomplish is to define an "arithmetic expression" algebraic data type, with an appropriate show instance. Note that you can make your expression type itself an instance of Num, with numeric literals wrapped in a "Literal" constructor, and operations like (+) returning their arguments combined with a constructor for the operation. Here's a quick, incomplete example:
data Expression a = Literal a
| Sum (Expression a) (Expression a)
| Product (Expression a) (Expression a)
deriving (Eq, Ord, Show)
instance (Num a) => Num (Expression a) where
x + y = Sum x y
x * y = Product x y
fromInteger x = Literal (fromInteger x)
evaluate (Literal x) = x
evaluate (Sum x y) = evaluate x + evaluate y
evaluate (Product x y) = evaluate x * evaluate y
integer :: Integer
integer = (1 + 2) * 3 + 4
expr :: Expression Integer
expr = (1 + 2) * 3 + 4
Trying it out in GHCi:
> integer
13
> evaluate expr
13
> expr
Sum (Product (Sum (Literal 1) (Literal 2)) (Literal 3)) (Literal 4)
Here's a way to think about this. Consider:
answer = 42
magic = 3
specialName :: Int -> String
specialName answer = "the answer to the ultimate question"
specialName magic = "the magic number"
specialName x = "just plain ol' " ++ show x
Can you see why this won't work? answer in the pattern match is a variable, distinct from answer at the outer scope. So instead, you'd have to write this like:
answer = 42
magic = 3
specialName :: Int -> String
specialName x | x == answer = "the answer to the ultimate question"
specialName x | x == magic = "the magic number"
specialName x = "just plain ol' " ++ show x
In fact, this is just what is going on when you write constants in a pattern. That is:
digitName :: Bool -> String
digitName 0 = "zero"
digitName 1 = "one"
digitName _ = "math is hard"
gets converted by the compiler to something equivalent to:
digitName :: Bool -> String
digitName x | x == 0 = "zero"
digitName x | x == 1 = "one"
digitName _ = "math is hard"
Since you want to match against the function bound to (+) rather than just bind anything to the symbol (+), you'd need to write your code as:
instance Show (t -> t-> t) where
show f | f == (+) = "plus"
show f | f == (-) = "minus"
But, this would require that functions were comparable for equality. And that is an undecidable problem in general.
You might counter that you are just asking the run-time system to compare function pointers, but at the language level, the Haskell programmer doesn't have access to pointers. In other words, you can't manipulate references to values in Haskell(*), only values themselves. This is the purity of Haskell, and gains referential transparency.
(*) MVars and other such objects in the IO monad are another matter, but their existence doesn't invalidate the point.
It overlaps because it treats (+) simply as a variable, meaning on the RHS the identifier + will be bound to the function you called show on.
There is no way to pattern match on functions the way you want.
Solved it myself with a mega hack.
instance (Num t) => Show (t -> t-> t) where
show op =
case (op 6 2) of
8 -> "plus"
4 -> "minus"
12 -> "times"
3 -> "divided"

Resources