How to optimize a transitive closure? - haskell

I have the following code, which I would like to optimize.
I'm particularly unhappy with nub :
deep (Op o x) = [f (Op o x)] ++ map (\y->(Op o y)) (sf x)
deep x = [x]
sf [x] = [[f x]]
sf (x:xs) = map (\y->(y:xs)) (deep x) ++ map (x:) (sf xs)
eqlst l
| l == ll = l
| otherwise = eqlst ll
where ll = nub $ l ++ (concat $ map deep l)
For a full understanding of this, I provide all my code, which is not so long:
module Nat ( Nat, Operator(Add, Mul), Exp(Const, Name, Op), toNat, fromNat) where
import Data.List(nub)
newtype Nat = Nat Integer deriving (Eq, Show, Ord)
toNat :: Integer -> Nat
toNat x | x <= 0 = error "Natural numbers should be positive."
| otherwise = Nat x
fromNat :: Nat -> Integer
fromNat (Nat n) = n
instance Num Nat where
fromInteger = toNat
x + y = toNat (fromNat x + fromNat y)
x - y = toNat (fromNat x - fromNat y)
x * y = toNat (fromNat x * fromNat y)
abs x = x
signum x = 1
data Operator = Add | Sub | Mul
deriving (Eq, Show, Ord)
data Exp = Const Nat | Name { name::String } | Op{ op::Operator, kids::[Exp] }
deriving (Eq, Ord)
precedence :: Exp -> Integer
precedence (Const x) = 10
precedence (Name x) = 10
precedence (Op Add x) = 6
precedence (Op Sub x) = 6
precedence (Op Mul x) = 7
instance Show Exp where
show Op { op = Add, kids = [x, y] } =
let left = if precedence x <= 6 then "(" ++ show x ++ ")" else show x in
let right = if precedence y <= 6 then "(" ++ show y ++ ")" else show y in
left ++ "+" ++ right
show Op { op = Sub, kids = [x, y] } =
let left = if precedence x <= 6 then "(" ++ show x ++ ")" else show x in
let right = if precedence y <= 6 then "(" ++ show y ++ ")" else show y in
left ++ "-" ++ right
show Op { op = Mul, kids = [x, y] } =
let left = if precedence x <= 7 then "(" ++ show x ++ ")" else show x in
let right = if precedence y <= 7 then "(" ++ show y ++ ")" else show y in
left ++ "∙" ++ right
show (Const (Nat x)) = show x
show (Name x) = x
show x = "wat"
instance Num Exp where
fromInteger = Const . toNat
(Const x) + (Const y) = Const (x+y)
x + y = simplify $ Op { op = Add, kids = [x, y] }
(Const x) - (Const y) = Const (x-y)
x - y = simplify $ Op { op = Sub, kids = [x, y] }
(Const x) * (Const y) = Const (x*y)
x * y = simplify $ Op { op = Mul, kids = [x, y] }
abs x = x
signum x = 1
simplify :: Exp -> Exp
simplify (Op Mul [x,1]) = x
simplify (Op Mul [1,x]) = x
simplify (Op Sub [x,y])
| x == y = 0
| otherwise = (Op Sub [x,y])
simplify x = x
f (Op Add [x,y]) = y+x
f (Op Sub [x,y]) = y-x
f (Op Mul [x,y]) = y*x
f x = x
deep (Op o x) = [f (Op o x)] ++ map (\y->(Op o y)) (sf x)
deep x = [x]
sf [x] = [[f x]]
sf (x:xs) = map (\y->(y:xs)) (deep x) ++ map (x:) (sf xs)
eqlst l
| l == ll = l
| otherwise = eqlst ll
where ll = nub $ l ++ (concat $ map deep l)
eq x = eqlst [x]
main = do
let x = Name "x";y = Name "x";z = Name "z";w = Name "w";q = Name "q"
let g = (x+y+(z+w)+q)+(x+y+(z+w)+q)+(x+y+(z+w)+q)+(x+y+(z+w)+q)
putStr $ unlines $ map show $ eq g
I also have a side question, about the function deep and sf that are using f::Exp->Exp. In the end, f should probably be f::[Exp]->[Exp].
Right now, f only performs one kind of transformation. In the end, I would like it to perform many kinds of transformations, for example :
a+b->b+a, (a+b)+c->a+(b+c), etc.

The function nub is inefficient since it only uses an Eq constraint and therefore has to compare every nondiscarded pair of elements. Using the more efficient Data.Set, which is based internally on sorted trees, should improve on this:
import qualified Data.Set as S
eqset s
| s == ss = s
| otherwise = eqset ss
where ss = S.unions $ s : map (S.fromList . deep) (S.toList s)
eqlst = S.toList . eqset . S.fromList

Related

Capture-avoiding substitution function -- Lambda calculus

I am trying to write a function that performs capture-avoiding substitution in Lambda calculus. The code compiles but does not spit out the correct answer. I've written what I expect the code to do, is my comprehension correct?
For example, I should get the following output for this input (numeral 0 is the Church numeral 0)
*Main> substitute "b" (numeral 0) example -- \a. \x. ((\y. a) x) b
\c. \a. (\a. c) a (\f. \x. x)
-- The incorrect result I actually got
\c. \c. (\f. \x. x) (x (\b. a))
NB \y is renamed to \a due to the substitution (\y.a)[N/b] (I think I have this covered in the code I have written, but please let me know if I am wrong.)
import Data.Char
import Data.List
type Var = String
data Term =
Variable Var
| Lambda Var Term
| Apply Term Term
-- deriving Show
instance Show Term where
show = pretty
example :: Term -- \a. \x. ((\y. a) x) b
example = Lambda "a"
(Lambda "x" (Apply (Apply (Lambda "y" (Variable "a"))
(Variable "x"))
(Variable "b")))
pretty :: Term -> String
pretty = f 0
where
f i (Variable x) = x
f i (Lambda x m) = if i /= 0 then "(" ++ s ++ ")" else s
where s = "\\" ++ x ++ ". " ++ f 0 m
f i (Apply n m) = if i == 2 then "(" ++ s ++ ")" else s
where s = f 1 n ++ " " ++ f 2 m
substitute :: Var -> Term -> Term -> Term
substitute x n (Variable y)
--if y = x, then leave n alone
| y == x = n
-- otherwise change to y
| otherwise = Variable y
substitute x n (Lambda y m)
--(\y.M)[N/x] = \y.M if y = x
| y == x = Lambda y m
--otherwise \z.(M[z/y][N/x]), where `z` is a fresh variable name
--generated by the `fresh` function, `z` must not be used in M or N,
--and `z` cannot be equal `x`. The `used` function checks if a
--variable name has been used in `Lambda y m`
| otherwise = Lambda newZ newM
where newZ = fresh(used(Lambda y m))
newM = substitute x n m
substitute x n (Apply m2 m1) = Apply newM2 newM1
where newM1 = substitute x n m2
newM2 = substitute x n m1
used :: Term -> [Var]
used (Variable n) = [n]
used (Lambda n t) = merge [n] (used t)
used (Apply t1 t2) = merge (used t1) (used t2)
variables :: [Var]
variables = [l:[] | l <- ['a'..'z']] ++
[l:show x | x <- [1..], l <- ['a'..'z']]
filterFreshVariables :: [Var] -> [Var] -> [Var]
filterFreshVariables lst = filter ( `notElem` lst)
fresh :: [Var] -> Var
fresh lst = head (filterFreshVariables lst variables)
recursiveNumeral :: Int -> Term
recursiveNumeral i
| i == 0 = Variable "x"
| i > 0 = Apply(Variable "f")(recursiveNumeral(i-1))
numeral :: Int -> Term
numeral i = Lambda "f" (Lambda "x" (recursiveNumeral i))
merge :: Ord a => [a] -> [a] -> [a]
merge (x : xs) (y : ys)
| x < y = x : merge xs (y : ys)
| otherwise = y : merge (x : xs) ys
merge xs [] = xs
merge [] ys = ys
This part in substitute x n (Lambda y m) is not correct:
the comment says "z must not be used in M or N", but there is nothing preventing that. newZ could be a variable in n, which leads to a problematic capture
the substitution z/y has not been done
| otherwise = Lambda newZ newM
where newZ = fresh(used(Lambda y m))
newM = substitute x n m
Fix:
"z must not be used in M or N":
newZ = fresh(used m `merge` used n)
"M[z/y][N/x]":
newM = substitute x n (substitute y (Variable newZ) m)
Put together:
| otherwise = Lambda newZ newM
where
newZ = fresh(used m `merge` used n)
newM = substitute x n (substitute y (Variable newZ) m)
Note that refreshing all bindings as done above makes it difficult to understand the result and to debug substitution. Actually y only needs to be refreshed if y is in n. Otherwise you can keep y, adding this clause:
| y `notElem` used n = Lambda y (substitute x n m)
Another idea would be to modify fresh to pick a name similar to the old one, e.g., by appending numbers until one doesn't clash.
There is still a bug I missed: newZ should also not be equal to x (the variable originally being substituted).
-- substitute [a -> \f. \x. x] in (\g. g), should be (\g. g)
ghci> substitute "a" (numeral 0) (Lambda "g" (Variable "g"))
\a. \g. \x. x
Two ways to address this:
add x to the set of variables to exclude newZ from:
newZ = fresh ([x] `merge` used m `merge` used n)
if you think about it, this bug only manifests itself when x is not in m, in which case there is nothing to substitute, so another way is to add one more branch skipping the work:
| x `notElem` used m = Lambda y m
Put together:
substitute x n (Lambda y m)
--(\y.M)[N/x] = \y.M if y = x
| y == x = Lambda y m
| x `notElem` used m = Lambda y m
| y `notElem` used n = Lambda y (substitute x n m)
| otherwise = Lambda newZ newM
where newZ = fresh(used m `merge` used n)
newM = substitute x n (substitute y (Variable newZ) m)
Output
ghci> example
\a. \x. (\y. a) x b
ghci> numeral 0
\f. \x. x
ghci> substitute "b" (numeral 0) example
\a. \c. (\y. a) c (\f. \x. x)
Note: I haven't tried to prove this code correct (exercise for the reader: define "correct"), there may still be bugs I missed. There must be some course about lambda calculus that has all the details and pitfalls but I haven't bothered to look.

Haskell: Evalute String containing a simple arithmetic expression to Int

I am learning Haskell, and I encounter a tricky problem which is evaluating String containing a simple arithmetic expression like (+) and (-) to int.
Take some for example:
"1+2+3" -> 6 , " " -> 0 .
I am trying to type the code. However, I cannot complete that. The following is my code.
evalExpr xs = foldl f 0 xs where
f acc x | x == "+" = (+) acc
| x == "-" = (-) acc
| x == " " = 0
| otherwise = read x ::Int
* In the expression: read x :: Int
In an equation for `f':
f acc x
| x == "+" = (+) acc
| x == "-" = (-) acc
| x == " " = 0
| otherwise = read x :: Int
In an equation for `evalExpr':
evalExpr xs
= foldl f 0 xs
where
f acc x
| x == "+" = (+) acc
| x == "-" = (-) acc
| x == " " = 0
| otherwise = read x :: Int
* Relevant bindings include
acc :: a1 (bound at A2.hs:24:8)
f :: a1 -> [Char] -> a1 -> a1 (bound at A2.hs:24:6)
Could someone help me? Thank you!
Your issue is that the result type of f is different in different branches, which is not allowed. In the first two it is (e.g.) Int -> Int, the type of (+) 3 (which is the same as \x -> 3 + x. The type of the third and fourth lines is just Int. These types are not the same.
Here is a simple solution.
data Token = Plus | Minus | Num Int
lex [] = Nothing
lex ('+':s) = Just (Plus,s)
lex ('-':s) = Just (Minus,s)
lex (num:s) | isDigit num = Just (Num k,rest) where
numstr a (d:s) | isDigit d = numstr (digitVal d:a) s
numstr a r = a,r
digits,rest = numstr [digitVal num] s
k = foldr 0 (\acc d -> acc*10 + d) digits
parse s = case lex s of
Nothing -> []
Just (x,s') -> x:parse s'
eval (Num n:r) = eval (Plus:Num n:r)
eval = eval' 0 where
eval' acc (Plus:Num n:r) = eval' (acc+n) r
eval' acc (Minus:Num n:r) = eval' (acc-n) r

non-exhaustive pattern error haskell

I'm trying to parse an input from user into my datatype:
type Var = String
data FProp = V Var
| No FProp
| Y FProp FProp
| O FProp FProp
| Si FProp FProp
| Sii FProp FProp deriving Read
using this function, by pattern matching:
f:: [String] -> FProp
f("(":"S":"i":"(":xs) = (Si (let x = fst (span (/= ")") xs) in f x) (let y = snd (span (/= ")") xs) in f y))
f("(":"Y":"(":xs) = (Y (let x = fst (span (/= ")") xs) in f x) (let y = snd (span (/= ")") xs) in f y))
f("(":"S":"i":"i":"(":xs) = (Sii (let x = fst (span (/= ")") xs) in f x) (let y = snd (span (/= ")") xs) in f y))
f("(":"O":"(":xs) = (O (let x = fst (span (/= ")") xs) in f x) (let y = snd (span (/= ")") xs) in f y))
f("(":"N":"O":"(":xs) = (No (f xs))
f ("(":"V":"(":xs) = (V(head xs))
The input would look like: "(Si (V(q)) (No (V(p))))" (equivalent to the formula: q -> ¬p).
It seemed like everything went fine, when I got this error: Non-exhaustive patterns in function f
¿Can I get some help in order to solve this?
I think it might have to do with the way I defined the last recursive case (the one for V).
The function you implemented is partial, not all cases are covered. You need to add a catch-all case and return an error.
To be able to do that, the function should return a type that allows modelling parsing failures (like Either Error FProp).
In my opinion you can create a much better parser with the parsec library. There are also many great tutorials you might want to investigate.

why would I get a "xx not in scope error" for this haskell code?

I write such a code, but get an error when compiling saying that "xx is not in scope".
test x =
let xx = 2 * x
in result
where result = replicate xx 3
I know I can fix it by using in replicate xx 3, however, code above is just a demo, the real code I am dealing with is like below:
nthElement :: (Ord b)=>(a->b)->Int->[a]->[a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals#(x:xs)
| k > (length vals) = vals
| otherwise = let left = [p | p<-vals, (op p) < (op x)]
midd = [p | p<-vals, (op p) == (op x)]
right = [p | p<-vals, (op p) > (op x)]
leftLen = length left
middLen = length midd
in result where result | leftLen >= k = (nthElement op k left) ++ midd ++ right
| (leftLen + middLen) >= k = left ++ midd ++ right
| otherwise = left ++ midd ++ nthElement op (k-middLen-leftLen) right
It seems that if I don't use the where clause, I have to use deeply nested if like this:
nthElement :: (Ord b)=>(a->b)->Int->[a]->[a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals#(x:xs)
| k > (length vals) = vals
| otherwise = let left = [p | p<-vals, (op p) < (op x)]
midd = [p | p<-vals, (op p) == (op x)]
right = [p | p<-vals, (op p) > (op x)]
leftLen = length left
middLen = length midd
in if leftLen >= k
then (nthElement op k left) ++ midd ++ right
else if (leftLen + middLen) >= k
then left ++ midd ++ right
else left ++ midd ++ nthElement op (k-middLen-leftLen) right
So, how could I change my code to fix the compiling bug as well as avoide using nested if?
You should think of this code more as
test x = {
let {
xx = 2 * x
} in {
result
}
} where {
result = replicate xx 3
}
instead of
test x = {
let {
xx = 2 * x
} in {
result where {
result = replicate xx 3
}
}
}
The where clause covers the entire definition of the function body and can only use names defined outside the function body (which arguments to test and test itself). The best way to fix this would be to move all definitions to the let or to the where. For your case, you'll probably want to move them all into the let:
test x =
let xx = 2 * x
result = replicate xx 3
in result
Or for your actual use case:
nthElement :: (Ord b) => (a -> b) -> Int -> [a] -> [a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals#(x:xs)
| k > (length vals) = vals
| otherwise = let left = [p | p<-vals, (op p) < (op x)]
midd = [p | p<-vals, (op p) == (op x)]
right = [p | p<-vals, (op p) > (op x)]
leftLen = length left
middLen = length midd
result | leftLen >= k = (nthElement op k left) ++ midd ++ right
| (leftLen + middLen) >= k = left ++ midd ++ right
| otherwise = left ++ midd ++ nthElement op (k-middLen-leftLen) right
in result
But, as this marches right off the side of the page, I would refactor it a bit to just use a single guard and a where:
nthElement :: (Ord b) => (a -> b) -> Int -> [a] -> [a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals#(x:xs)
| k > length vals = vals
| k <= leftLen = nth k left ++ midd ++ right
| k <= leftMiddLen = left ++ midd ++ right
| otherwise = left ++ midd ++ nth kR right
where
opx = op x
left = [p | p <- vals, op p < opx]
midd = [p | p <- vals, op p == opx]
right = [p | p <- vals, op p > opx]
leftLen = length left
middLen = length midd
leftMiddLen = leftLen + middLen
nth = nthElement op
kR = k - leftMiddLen
98% of this is just stylistic, you may not like it this way, but I find it a lot easier to read. In particuarly, I would say that the 2% that isn't just style is collapsing the guards down to a single level, it makes your intentions much more clear. Since Haskell is lazy you also don't have to worry about computing anything until the value is actually used.
nthElement :: (Ord b)=>(a->b)->Int->[a]->[a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals#(x:xs)
| k > (length vals) = vals
| otherwise = let left = [p | p<-vals, (op p) < (op x)]
midd = [p | p<-vals, (op p) == (op x)]
right = [p | p<-vals, (op p) > (op x)]
leftLen = length left
middLen = length midd
result | leftLen >= k = (nthElement op k left) ++ midd ++ right
| (leftLen + middLen) >= k = left ++ midd ++ right
| otherwise = left ++ midd ++ nthElement op (k-middLen-leftLen) right
in result

I do not understand this error haskell

My code receives a list of values ​​in hexadecimal and i have to pass them to binary and put each result in a list but I have these two errors and i dont know how to fix them
Pixels.hs:121:29:
Occurs check: cannot construct the infinite type:
t0 = Bool -> [a1] -> t0
In the return type of a call of `modA'
Probable cause: `modA' is applied to too many arguments
In the expression:
modA (o ++ [(k `mod` 2)]) (l + 1) (k `div` 2) otherwise o
In an equation for `modA':
modA o l k
| l < 8 = modA (o ++ [(k `mod` 2)]) (l + 1) (k `div` 2) otherwise o
Pixels.hs:126:89:
Couldn't match expected type `[a0]'
with actual type `Bool -> t1 -> [[a1]] -> [a0] -> t0'
In the first argument of `(++)', namely `f'
In the fourth argument of `f', namely
`(f
++
[(psr (head (e1)))
++
(psr (head (e2)))
++ (psr (head (e3))) ++ (psr (head (e4))) ++ (psr (head (e5)))])'
In the expression:
f otherwise
convertir
[tail (e1), tail (e2), tail (e3), tail (e4), ....]
(f
++
[(psr (head (e1)))
++
(psr (head (e2)))
++ (psr (head (e3))) ++ (psr (head (e4))) ++ (psr (head (e5)))])
Failed, modules loaded: none.
here is the code
rInt :: String -> Int
rInt = read
font:: Char -> Pixels
font a = let x= ord a in
if x>=0 || x<=31 || x>=126 then ["*****","*****","*****","*****","*****","*****","*****"]
else
auxfont (fontBitmap!!(x-32))
where
auxfont b = let y = map trns (map rInt (map show b)) in
convertir y []
trns z = modA [] 1 z
modA o l k
| l < 8 = modA (o++[(k `mod` 2)]) (l+1) (k `div` 2)
otherwise o
convertir (e1:e2:e3:e4:e5) f
| null e1 = f
otherwise convertir [tail(e1),tail(e2),tail(e3),tail(e4),tail(e5)] (f++[(psr(head(e1)))++(psr(head(e2)))++(psr(head(e3)))++(psr(head(e4)))++(psr(head(e5)))])
psr 0 = " "
psr 1 = "*"
Your syntax is wrong, you need a | before otherwise:
foo x y z | x > y = ...
| otherwise = ...

Resources