How to compare two natural numbers in Agda with standard library (like N -> N -> Bool)? - comparison-operators

I can compare two natural numbers by writing comparator manually:
is-≤ : ℕ → ℕ → Bool
is-≤ zero _ = true
is-≤ (suc _) zero = false
is-≤ (suc x) (suc y) = is-≤ x y
However, I hope that there is something similar in the standard library so I don't write that every time.
I was able to find _≤_ operator in Data.Nat, but it's a parametrized type which basically contains "proof" that one specific number is less than the other (similar to _≡_). Is there a way to use it or something else to understand which number is smaller than the other "in runtime" (e.g. return corresponding Bool)?
The bigger problem I'm trying to solve:
As a part of my assignment, I'm writing a readNat : List Char → Maybe (ℕ × List Char) function. It tries to read natural number from the beginning of the list; will later become part of sscanf.
I want to implement digit : Char → Maybe ℕ helper function which would parse a single decimal digit.
In order to do so I want to compare primCharToNat c with primCharToNat '0', primCharToNat '1' and decide whether to return None or (primCharToNat c) ∸ (primCharToNat '0')

A solution suggested by #gallais in comments:
open import Data.Nat using (ℕ; _≤?_)
open import Data.Bool using (Bool)
open import Relation.Nullary using (Dec)
is-≤ : ℕ → ℕ → Bool
is-≤ a b with a ≤? b
... | Dec.yes _ = Bool.true
... | Dec.no _ = Bool.false
Here we match on a proof that _≤_ is decidable using the with-clause. One can use it similarly in more complex functions.
Suggestion by #user3237465 in comments to this answer: you can also use shorthand ⌊_⌋ (\clL/\clR or \lfloor/\rfloor) which does this exact pattern matching and eliminate the need for is-≤:
open import Data.Nat using (ℕ; _≤?_)
open import Data.Bool using (Bool)
open import Relation.Nullary.Decidable using (⌊_⌋)
is-≤ : ℕ → ℕ → Bool
is-≤ a b = ⌊ a ≤? b ⌋
Another approach is to use compare, it also provides more information (e.g. the difference between two numbers):
open import Data.Nat using (ℕ; compare)
open import Data.Bool using (Bool)
open import Relation.Nullary using (Dec)
is-≤' : ℕ → ℕ → Bool
is-≤' a b with compare a b
... | Data.Nat.greater _ _ = Bool.false
... | _ = Bool.true
is-≤3' : ℕ → Bool
is-≤3' a with 3 | compare a 3
... | _ | Data.Nat.greater _ _ = Bool.false
... | _ | _ = Bool.true
Note that compareing with a constant value requires extra caution for some reason.

Related

How do I use (#) operator in Haskell as I get parse error on input?

I am new to Haskell and I am trying to calculate the maximum segment sum,
(#) :: Int -> Int -> Int
x # y = 0 `max` (x + y)
mss2 :: [Int] -> Int
mss2 = maximum . scanr (#) 0
The error is
No Modules Loaded for (#)
I found this snippet in Richard Bird's text.
What am I missing here?
Are there other ways to declare/overload the operators, is my approach wrong?
It appears that in the context of that book, (#) is being used as a stand-in for some binary operator such as (+) or (<>), even though this is not actually legal Haskell syntax†.
For questions about Haskell syntax, it’s helpful to consult the Haskell 2010 Report.
In Ch. 2 Lexical Structure, under §2.2 Lexical Program Structure, you can find # in the grammar of symbols that may appear in an operator name:
symbol → ascSymbol | uniSymbol⟨special | _ | " | '⟩
ascSymbol → ! | # | $ | % | & | ⋆ | + | . | / | < | = | > | ? | #
| \ | ^ | | | - | ~ | :
And §2.4 Lexical Structure: Identifiers and Operators defines valid operator names to include such symbols:
varsym → ( symbol⟨:⟩ {symbol} )⟨reservedop | dashes⟩
consym → ( : {symbol} )⟨reservedop⟩
However, the subscript in angle brackets denotes a “difference” or exclusion, so this disallows a list of reserved identifiers. Under the production reservedop you can find that # appears in that list:
reservedop → .. | : | :: | = | \ | | | <- | -> | # | ~ | =>
The reason is that the # symbol denotes an “as” pattern, described in §3.17.2.8 Informal Semantics of Pattern Matching:
Matching an as-pattern var#apat against a value v is the result of matching apat against v, augmented with the binding of var to v.
As patterns are very useful for controlling the sharing of values and making certain definitions more concise, e.g.:
-- | Merge two sorted lists.
merge :: (Ord a) => [a] -> [a] -> [a]
-- ‘as0’ & ‘bs0’ denote the original input lists.
-- ‘as’ & ‘bs’ denote their tails.
merge as0#(a : as) bs0#(b : bs) = case compare a b of
-- ‘as0’ passes along the same list cell;
-- repeating ‘a : as’ would allocate a /new/ cell.
GT -> b : merge as0 bs
_ -> a : merge as bs0
merge [] bs0 = bs0
merge as0 [] = as0
Therefore, the definition:
x # y = 0 `max` (x + y)
Or more conventionally written x#y = …, is equivalent to defining two variables referring to the same value, which furthermore is defined recursively:
x = 0 `max` (x + y)
y = x
Without the type signature Int -> Int -> Int, this definition would be accepted, defining x, y :: (Ord a, Num a) => a, but attempting to evaluate either variable would produce an infinite loop, since this is “unproductive” recursion.
The solution is to use a non-reserved symbol as your operator name instead, such as <#> or +..
† I can’t find a citation for this, but it’s possible that GHC used to accept this syntax, even though it was also disallowed by the Haskell 98 Report which was current at the time the first edition of this book came out, and that this example code just wasn’t updated for the second edition.

Why do we need containers?

(As an excuse: the title mimics the title of Why do we need monads?)
There are containers [1] (and indexed ones [2]) (and hasochistic ones [3]) and descriptions.[4] But containers are problematic [5] and to my very small experience it's harder to think in terms of containers than in terms of descriptions. The type of non-indexed containers is isomorphic to Σ — that's quite too unspecific. The shapes-and-positions description helps, but in
⟦_⟧ᶜ : ∀ {α β γ} -> Container α β -> Set γ -> Set (α ⊔ β ⊔ γ)
⟦ Sh ◃ Pos ⟧ᶜ A = ∃ λ sh -> Pos sh -> A
Kᶜ : ∀ {α β} -> Set α -> Container α β
Kᶜ A = A ◃ const (Lift ⊥)
we are essentially using Σ rather than shapes and positions.
The type of strictly-positive free monads over containers has a rather straightforward definition, but the type of Freer monads looks simpler to me (and in a sense Freer monads are even better than usual Free monads as described in the paper [6]).
So what can we do with containers in a nicer way than with descriptions or something else?
References
Abbott, Michael, Thorsten Altenkirch, and Neil Ghani. "Containers: Constructing strictly positive types." Theoretical Computer Science 342, no. 1 (2005): 3-27.
Altenkirch, Thorsten, Neil Ghani, Peter Hancock, Conor McBride, and PETER MORRIS. 2015. “Indexed Containers.” Journal of Functional Programming 25. Cambridge University Press: e5. doi:10.1017/S095679681500009X.
McBride, Conor. "hasochistic containers (a first attempt)." Jun, 2015.
Chapman, James, Pierre-Evariste Dagand, Conor Mcbride, and Peter Morris. "The gentle art of levitation." In ICFP 2010, pp. 3-14. 2010.
Francesco. "W-types: good news and bad news." Mar 2010.
Kiselyov, Oleg, and Hiromi Ishii. "Freer monads, more extensible effects." In 8th ACM SIGPLAN Symposium on Haskell, Haskell 2015, pp. 94-105. Association for Computing Machinery, Inc, 2015.
To my mind, the value of containers (as in container theory) is their uniformity. That uniformity gives considerable scope to use container representations as the basis for executable specifications, and perhaps even machine-assisted program derivation.
Containers: a theoretical tool, not a good run-time data representation strategy
I would not recommend fixpoints of (normalized) containers as a good general purpose way to implement recursive data structures. That is, it is helpful to know that a given functor has (up to iso) a presentation as a container, because it tells you that generic container functionality (which is easily implemented, once for all, thanks to the uniformity) can be instantiated to your particular functor, and what behaviour you should expect. But that's not to say that a container implementation will be efficient in any practical way. Indeed, I generally prefer first-order encodings (tags and tuples, rather than functions) of first-order data.
To fix terminology, let us say that the type Cont of containers (on Set, but other categories are available) is given by a constructor <| packing two fields, shapes and positions
S : Set
P : S -> Set
(This is the same signature of data which is used to determine a Sigma type, or a Pi type, or a W type, but that does not mean that containers are the same as any of these things, or that these things are the same as each other.)
The interpretation of such a thing as a functor is given by
[_]C : Cont -> Set -> Set
[ S <| P ]C X = Sg S \ s -> P s -> X -- I'd prefer (s : S) * (P s -> X)
mapC : (C : Cont){X Y : Set} -> (X -> Y) -> [ C ]C X -> [ C ]C Y
mapC (S <| P) f (s , k) = (s , f o k) -- o is composition
And we're already winning. That's map implemented once for all. What's more, the functor laws hold by computation alone. There is no need for recursion on the structure of types to construct the operation, or to prove the laws.
Descriptions are denormalized containers
Nobody is attempting to claim that, operationally, Nat <| Fin gives an efficient implementation of lists, just that by making that identification we learn something useful about the structure of lists.
Let me say something about descriptions. For the benefit of lazy readers, let me reconstruct them.
data Desc : Set1 where
var : Desc
sg pi : (A : Set)(D : A -> Desc) -> Desc
one : Desc -- could be Pi with A = Zero
_*_ : Desc -> Desc -> Desc -- could be Pi with A = Bool
con : Set -> Desc -- constant descriptions as singleton tuples
con A = sg A \ _ -> one
_+_ : Desc -> Desc -> Desc -- disjoint sums by pairing with a tag
S + T = sg Two \ { true -> S ; false -> T }
Values in Desc describe functors whose fixpoints give datatypes. Which functors do they describe?
[_]D : Desc -> Set -> Set
[ var ]D X = X
[ sg A D ]D X = Sg A \ a -> [ D a ]D X
[ pi A D ]D X = (a : A) -> [ D a ]D X
[ one ]D X = One
[ D * D' ]D X = Sg ([ D ]D X) \ _ -> [ D' ]D X
mapD : (D : Desc){X Y : Set} -> (X -> Y) -> [ D ]D X -> [ D ]D Y
mapD var f x = f x
mapD (sg A D) f (a , d) = (a , mapD (D a) f d)
mapD (pi A D) f g = \ a -> mapD (D a) f (g a)
mapD one f <> = <>
mapD (D * D') f (d , d') = (mapD D f d , mapD D' f d')
We inevitably have to work by recursion over descriptions, so it's harder work. The functor laws, too, do not come for free. We get a better representation of the data, operationally, because we don't need to resort to functional encodings when concrete tuples will do. But we have to work harder to write programs.
Note that every container has a description:
sg S \ s -> pi (P s) \ _ -> var
But it's also true that every description has a presentation as an isomorphic container.
ShD : Desc -> Set
ShD D = [ D ]D One
PosD : (D : Desc) -> ShD D -> Set
PosD var <> = One
PosD (sg A D) (a , d) = PosD (D a) d
PosD (pi A D) f = Sg A \ a -> PosD (D a) (f a)
PosD one <> = Zero
PosD (D * D') (d , d') = PosD D d + PosD D' d'
ContD : Desc -> Cont
ContD D = ShD D <| PosD D
That's to say, containers are a normal form for descriptions. It's an exercise to show that [ D ]D X is naturally isomorphic to [ ContD D ]C X. That makes life easier, because to say what to do for descriptions, it's enough in principle to say what to do for their normal forms, containers. The above mapD operation could, in principle, be obtained by fusing the isomorphisms to the uniform definition of mapC.
Differential structure: containers show the way
Similarly, if we have a notion of equality, we can say what one-hole contexts are for containers uniformly
_-[_] : (X : Set) -> X -> Set
X -[ x ] = Sg X \ x' -> (x == x') -> Zero
dC : Cont -> Cont
dC (S <| P) = (Sg S P) <| (\ { (s , p) -> P s -[ p ] })
That is, the shape of a one-hole context in a container is the pair of the shape of the original container and the position of the hole; the positions are the original positions apart from that of the hole. That's the proof-relevant version of "multiply by the index, decrement the index" when differentiating power series.
This uniform treatment gives us the specification from which we can derive the centuries-old program to compute the derivative of a polynomial.
dD : Desc -> Desc
dD var = one
dD (sg A D) = sg A \ a -> dD (D a)
dD (pi A D) = sg A \ a -> (pi (A -[ a ]) \ { (a' , _) -> D a' }) * dD (D a)
dD one = con Zero
dD (D * D') = (dD D * D') + (D * dD D')
How can I check that my derivative operator for descriptions is correct? By checking it against the derivative of containers!
Don't fall into the trap of thinking that just because a presentation of some idea is not operationally helpful that it cannot be conceptually helpful.
On "Freer" monads
One last thing. The Freer trick amounts to rearranging an arbitrary functor in a particular way (switching to Haskell)
data Obfuncscate f x where
(:<) :: forall p. f p -> (p -> x) -> Obfuncscate f x
but this is not an alternative to containers. This is a slight currying of a container presentation. If we had strong existentials and dependent types, we could write
data Obfuncscate f x where
(:<) :: pi (s :: exists p. f p) -> (fst s -> x) -> Obfuncscate f x
so that (exists p. f p) represents shapes (where you can choose your representation of positions, then mark each place with its position), and fst picks out the existential witness from a shape (the position representation you chose). It has the merit of being obviously strictly positive exactly because it's a container presentation.
In Haskell, of course, you have to curry out the existential, which fortunately leaves a dependency only on the type projection. It's the weakness of the existential which justifies the equivalence of Obfuncscate f and f. If you try the same trick in a dependent type theory with strong existentials, the encoding loses its uniqueness because you can project and tell apart different choices of representation for positions. That is, I can represent Just 3 by
Just () :< const 3
or by
Just True :< \ b -> if b then 3 else 5
and in Coq, say, these are provably distinct.
Challenge: characterizing polymorphic functions
Every polymorphic function between container types is given in a particular way. There's that uniformity working to clarify our understanding again.
If you have some
f : {X : Set} -> [ S <| T ]C X -> [ S' <| T' ]C X
it is (extensionally) given by the following data, which make no mention of elements whatsoever:
toS : S -> S'
fromP : (s : S) -> P' (toS s) -> P s
f (s , k) = (toS s , k o fromP s)
That is, the only way to define a polymorphic function between containers is to say how to translate input shapes to output shapes, then say how to fill output positions from input positions.
For your preferred representation of strictly positive functors, give a similarly tight characterisation of the polymorphic functions which eliminates abstraction over the element type. (For descriptions, I would use exactly their reducability to containers.)
Challenge: capturing "transposability"
Given two functors, f and g, it is easy to say what their composition f o g is: (f o g) x wraps up things in f (g x), giving us "f-structures of g-structures". But can you readily impose the extra condition that all of the g structures stored in the f structure have the same shape?
Let's say that f >< g captures the transposable fragment of f o g, where all the g shapes are the same, so that we can just as well turn the thing into a g-structure of f-structures. E.g., while [] o [] gives ragged lists of lists, [] >< [] gives rectangular matrices; [] >< Maybe gives lists which are either all Nothing or all Just.
Give >< for your preferred representation of strictly positive functors. For containers, it's this easy.
(S <| P) >< (S' <| P') = (S * S') <| \ { (s , s') -> P s * P' s' }
Conclusion
Containers, in their normalized Sigma-then-Pi form, are not intended to be an efficient machine representation of data. But the knowledge that a given functor, implemented however, has a presentation as a container helps us understand its structure and give it useful equipment. Many useful constructions can be given abstractly for containers, once for all, when they must be given case-by-case for other presentations. So, yes, it is a good idea to learn about containers, if only to grasp the rationale behind the more specific constructions you actually implement.

Haskell: Why I can load this file in ghci but when I try to do the same in hugs I get a syntax error?

This is the file I am trying to load:
import Data.List (foldl')
import Text.Printf (printf)
import Data.Char (ord)
--data IntParsedStr = Int | ParsingError
--data ParsingError = ParsingError String
asInt :: String -> Either String Integer
asInt "" = Left "Empty string"
asInt xs#(x:xt) | x == '-' = either Left (Right . ((-1) *)) (asInt' xt)
| otherwise = either Left Right (asInt' xs)
where asInt' :: String -> Either String Integer
asInt' "" = Left "No digits"
asInt' xs = foldl' step (Right 0) xs
where step :: Either String Integer -> Char -> Either String Integer
step (Left e) _ = Left e
step (Right ac) c = either Left (Right . (10 * ac + ) . fromIntegral) (charAsInt c)
charAsInt :: Char -> Either String Int
charAsInt c | between (ord '0') (ord c) (ord '9') = Right $ ord c - ord '0'
| otherwise = Left $ printf "'%c' is not a digit" c
checkPrecision str = either error ((str == ). show) (asInt str)
between :: Ord t => t -> t -> t -> Bool
between a b c = a <= b && b <= c
It loads without any problem in ghci but in hugs I get this error:
ERROR "folds.hs":17 - Syntax error in expression (unexpected `)')
Line 17 is the last in the definition of asInt function
Edit:
Hi!
I recently founded that this is in fact a known hugs issue as said in this question
where there is a link to the Hugs 98 Users Guide where says that
Legal expressions like (a+b+) and (a*b+) are rejected.
I believe this is a bug in Hugs, not a liberality of GHC. The Haskell 98 report (appropriate in the context of Hugs usage) says
Syntactic precedence rules apply to sections as follows. (op e) is legal if and only if (x op e) parses in the same way as (x op (e)); and similarly for (e op). For example, (*a+b) is syntactically invalid, but (+a*b) and (*(a+b)) are valid. Because (+) is left associative, (a+b+) is syntactically correct, but (+a+b) is not; the latter may legally be written as (+(a+b)).
I interpret that as allowing (10 * ac + ) since both (*) and (+) are left associative, and indeed (*) has higher precedence.
As pointed out in the comments, ((10 * ac) + ) is accepted by both, so is a workaround.
Interestingly, this isn't listed in the Hugs vs Haskell 98 page, so maybe Mark P. Jones reads this section of the report differently to me. Certainly I can forgive him for this; Gofer implemented constructor classes long before Haskell allowed them, and Hugs is still faster than GHCi at compilation, and still gives better error messages.

Haskell calculator - order of operations

I am very new to Haskell and I need to make a working calculator what will give answers to expressions like: 2+3*(5+12)
I have something that manages to calculate more or less but I have a problem with order of operations. I have no idea how to do it. Here is my code:
import Text.Regex.Posix
import Data.Maybe
oblicz :: String -> Double
oblicz str = eval (Nothing, None) $ map convertToExpression $ ( tokenize str )
eval :: (Maybe Double,Expression)->[Expression]->Double
eval (Nothing, _) ((Variable v):reszta) = eval (Just v, None) reszta
eval (Just aktualnyWynik, None) ((Operator o):reszta) = eval ((Just aktualnyWynik), (Operator o)) reszta
eval (Just aktualnyWynik, (Operator o)) ((Variable v):reszta) = eval (Just $ o aktualnyWynik v , None) reszta
eval (aktualnyWynik, operator) (LeftParenthesis:reszta)
= eval (aktualnyWynik, operator) ((Variable (eval (Nothing, None) reszta)):(getPartAfterParentheses reszta))
eval (Just aktualnyWynik, _) [] = aktualnyWynik
eval (Just aktualnyWynik, _) (RightParenthesis:_) = aktualnyWynik
data Expression = Operator (Double->Double->Double)
| Variable Double
| LeftParenthesis
| RightParenthesis
| None
tokenize :: String -> [String]
tokenize expression = getAllTextMatches(expression =~ "([0-9]+|\\(|\\)|\\+|-|%|/|\\*)" :: AllTextMatches [] String)
convertToExpression :: String -> Expression
convertToExpression "-" = Operator (-)
convertToExpression "+" = Operator (+)
convertToExpression "*" = Operator (*)
convertToExpression "/" = Operator (/)
convertToExpression "(" = LeftParenthesis
convertToExpression ")" = RightParenthesis
convertToExpression variable = Variable (read variable)
getPartAfterParentheses :: [Expression] -> [Expression]
getPartAfterParentheses [] = []
getPartAfterParentheses (RightParenthesis:expressionsList) = expressionsList
getPartAfterParentheses (LeftParenthesis:expressionsList) = getPartAfterParentheses (getPartAfterParentheses expressionsList)
getPartAfterParentheses (expression:expressionsList) = getPartAfterParentheses expressionsList
I thought maybe I could create two stacks - one with numbers and one with operators. While reading the expression, I could push numbers on one stack and operators on another. When it is an operator I would check if there is something already on the stack and if there is check if I should pop it from the stack and do the math or not - just like in onp notation.
Unfortunately, as I said, I am VERY new to haskell and have no clue how to go about writing this.
Any hints or help would be nice :)
Pushing things on different stacks sure feels very much a prcedural thing to do, and that's generally not nice in Haskell. (Stacks can be realised as lists, which works quite nice in a purely functional fashion. Even real mutable state can be fine if only as an optimisation, but if more than one object needs to be modified at a time then this isn't exactly enjoyable.)
The preferrable way would be to build up a tree representing the expression.
type DInfix = Double -> Double -> Double -- for readability's sake
data ExprTree = Op DInfix ExprTree ExprTree
| Value Double
Evaluating this tree is basically evalTree (Op c t1 t2) = c (evalTree t1) (evalTree t2), i.e. ExprTree->Double right away.
To build the tree up, the crucial point: get the operator fixities right. Different operators have different fixity. I'd put that information in the Operator field:
type Fixity = Int
data Expression = Operator (Double->Double->Double) Fixity
| ...
which then requires e.g.
...
convertToExpression "+" = Operator (+) 6
convertToExpression "*" = Operator (*) 7
...
(Those are the fixities that Haskell itself has for the operators. You can :i + in GHCi to see them.)
Then you'd build the tree.
toExprTree :: [Expression] -> ExprTree
Obvious base case:
toExprTree [Variable v] = Value v
You might continue with
toExprTree (Variable v : Operator c _ : exprs) = Op c (Value v) (toExprTree exprs)
But that's actually not right: for e.g. 4 * 3 + 2 it would give 4 * (3 + 2). We actually need to bring the 4 * down the remaining expressions tree, as deep as the fixities are lower. So the tree needs to know about that as well
data ExprTree = Op DInfix Fixity ExprTree ExprTree
| Value Double
mergeOpL :: Double -> DInfix -> Fixity -> ExprTree -> ExprTree
mergeOpL v c f t#(Op c' f' t' t'')
| c > c' = Op c' f' (mergeOpL v c f t') t''
mergeOpL v c f t = Op c f (Value v) t
What remains to be done is handling parentheses. You'd need to take a whole matching-brackets expression and assign it a tree-fixity of, say tight = 100 :: Fixity.
As a note: such a tokenisation - manual parsing workflow is pretty cumbersome, regardless how nicely functional you do it. Haskell has powerful parser-combinator libraries like parsec, which take most of the work and bookkeeping off you.
What you need to solve this problem is the Shunting-yard Algorithm of Edsger Dijstra as described at http://www.wcipeg.com/wiki/Shunting_yard_algorithm. You can see my implementation at the bottom of this file.
If you are limiting your self to just +,-,*,/ you can also solve the problem using the usual trick in most intro to compiler examples simply parsing into two different non-terminals, ofter called term and product to build the correct tree. This get unwieldy if you have to deal with a lot of operators or they are user defined.

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

Resources