Syntax for partial function composition - haskell

module Luhn (isValid) where
import qualified Data.Char as C
isAsciiAlpha :: Char -> Bool
isAsciiAlpha = C.isAsciiLower || C.isAsciiUpper
isValid :: String -> Bool
isValid n
| any ((isAsciiAlpha || C.isSpace) . not) n = False
| otherwise = ys > 1 && sum xxs `mod` 10 == 0
where
xs = reverse [c | c <- n, isAsciiAlpha c]
ys = length xs
zs = zip xs (cycle [1, 2])
xxs = [convert x y | (x, y) <- zs]
convert :: Char -> Int -> Int
convert c mul =
do
let n = C.digitToInt c
case () of
_
| mul == 2 && (n > 4) -> n * mul - 9
| otherwise -> n * mul
I'm struggling with this line: any ((isAsciiAlpha || C.isSpace) . not) n = False. What I want is pretty obvious; find if any of the characters is something other than an ASCII alphabet or a space.
In spite of trying various syntaxes, I keep getting compilation error on this line, something like
• Couldn't match expected type ‘Bool’
with actual type ‘Char -> Bool’

You can not use (||) :: Bool -> Bool -> Bool on two functions: the parameters should be both Bools. What you can do is construct a function that maps a character c on isAsciiAlpha c || C.isSpace c, so \c -> isAsciiAlpha c || C.isSpace c, or you can use liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c with liftA2 (||) isAsciiAlpha C.isSpace. The not :: Bool -> Bool should also be applied on the result of the function, so:
import Control.Applicative(liftA2)
isAsciiAlpha :: Char -> Bool
isAsciiAlpha = liftA2 (||) C.isAsciiLower C.isAsciiUpper
isValid :: String -> Bool
isValid n
| any (not . liftA2 (||) isAsciiAlpha C.isSpace) n = False
| otherwise = ys > 1 && sum xxs `mod` 10 == 0
where -- …
You can also make use of (<||>) :: Applicative a => a Bool -> a Bool -> a Bool or its shortcircuitng version (||^) :: Monad m => m Bool -> m Bool -> m Bool of the protolude package.

Related

How to pass not a function that returns a boolean in another function?

I want to negate a function in the if clause of another function like bellow:
isBig :: Integer -> Bool
isBig n = n > 9999
function :: Integer -> Integer
function n =
if not isBig n then ... else ...
It complies when it's just 'if isBig n then else' but I'm not sure why it doesn't work for 'not isBig' as I get this error:
*Couldn't match expected type Bool' with actual type Integer -> Bool'
Many thanks in advance.
You want not (isBig n). not isBig n tries to pass two arguments to not, both isBig and n. isBig is an Integer -> Bool but a Bool is expected, hence the error.
In general, function application in Haskell is left-associative, meaning that an expression like this:
f 2 3 5
Is parsed like this:
(((f 2) 3) 5)
Likewise, the arrows in function types are right-associative, so for example if we had this definition for f:
f :: Int -> Int -> Int -> Int
f x y z = x * y + z
That type signature is the same as:
f :: Int -> (Int -> (Int -> Int))
So it looks like this as you apply more arguments:
f :: Int -> (Int -> (Int -> Int))
(f 2) :: (Int -> (Int -> Int))
((f 2) 3) :: (Int -> Int)
(((f 2) 3) 5 :: Int
==
f :: Int -> Int -> Int -> Int
f 2 :: Int -> Int -> Int
f 2 3 :: Int -> Int
f 2 3 5 :: Int
When you’re applying a chain of functions to an argument, you end up with parentheses associating to the right:
f (g (h x))
In this case it’s common to use the $ operator, which is right-associative and has low precedence, just to reduce the nesting of brackets:
f $ g $ h x
And you can do so in your case: not $ isBig n
You can also use composition to factor out the chain of functions and apply it to different arguments elsewhere:
fgh = f . g . h
fgh x
==
(f . g . h) x
==
f (g (h x))
isNotBig = not . isBig
isNotBig n
==
(not . isBig) n
==
not (isBig n)

traversal of boolean AST in Haskell

I am having trouble completing a task where I am to create a function that uses a generalised fold function to evaluate a boolean AST. I will show you some examples to illustrate.
First, an example of what I want, but for an AST that sums integers:
data Expr = Val Int | Add Expr Expr deriving Show
folde :: (Int -> a) -> (a -> a -> a) -> Expr -> a
folde f g (Val x) = f x
folde f g (Add x y) = g (folde f g x) (folde f g y)
eval :: Expr -> Int
eval expr = folde (\x -> x) (\x y -> x + y) expr
This works fine.
Now for the boolean AST, and the folding function:
data Bexp = T | F | And Bexp Bexp | Or Bexp Bexp deriving (Ord, Eq)
foldb :: a -> a -> (a -> a -> a) -> (a -> a -> a) -> Bexp -> a
foldb t f a o T = t
foldb t f a o F = f
foldb t f a o (And x y) = a (foldb t f a o x) (foldb t f a o y)
foldb t f a o (Or x y) = o (foldb t f a o x) (foldb t f a o y)
What I am having trouble with, is creating a function that does the same as the eval function does for the simple AST above, that is, using the foldb function with some lambdas to evaluate whether the Bexp expression is either T or F.
I don't understand why this function doesn't work:
evb :: Bexp -> Bool
evb bexp = foldb (\_ -> True) (\_ -> False) (\x y -> x == T && y == T) (\x y -> x == T || y == T) bexp
GHCi doesn't even wanna to compile it because of type error.
Thanks in advance.
The code does't compile for few reasons.
-- Observe type signatures.
foldb :: a -> a -> (a -> a -> a) -> (a -> a -> a) -> Bexp -> a
evb bexp = foldb (\_ -> True) (\_ -> False) (\x y -> x == T && y == T) (\x y -> x == T || y == T) bexp
If foldb takes its first argument as a Function x -> Bool then from the type signature of foldb a is of type function but observe this (\x y -> x == T && y == T) here you used a as Bexp, which don't match at all.
a = Bexp from (\x y -> x == T && y == T)
a = x -> Bool from (\_ -> True)
And also the return type of evb is Bool, but from your argument passing to foldb a can be 2 things & the compiler is confused to pick the right type.
If we want to use foldb to produce a Bool at the very end, we need to choose a = Bool in its type. So, we are now using
foldb :: Bool
-> Bool
-> (Bool -> Bool -> Bool)
-> (Bool -> Bool -> Bool)
-> Bexp
-> Bool
Hence, foldb (\_->True) (\_->False) ... is wrong since the first two arguments must be booleans, not functions. We need something like foldb True False ....
The next two parameters must be boolean binary operators like \x y -> x && y, which can be written as (&&) for short.
We finally get:
evb :: Bexp -> Bool
evb bexp = foldb True False (&&) (||)

Creating a boolean to return true for Strings starting with a char and the proceeding values being either a char a digit or an underscore

I've been trying to create Boolean that returns True for strings consisting of
a letter followed by one or more letters, digits or underscore characters.
I get the following compile error:
"Couldn't match expected type Char -> Bool
with actual type Bool
Possible cause: or is applied to too many arguments "
isIdentifier :: String -> Bool
isIdentifier [] = False
isIdentifier (x:[]) = False
isIdentifier(x:xs)
| isAlpha x && length(filter(or [isAlpha, isDigit, (=='_')]) xs ) == length xs = True
| otherwise = False
This is my code. I know from the error message that I need to somehow apply or to xs but I don't know how to do so without affecting the filter function.
I was wondering if there were better ways of setting up my function.
The type of or is:
Prelude Data.Char> :t or
or :: Foldable t => t Bool -> Bool
It requires some Foldable container of Bool values, such as [Bool], as input.
The input it receives, however, is a list of predicates:
Prelude Data.Char> :t [isAlpha, isDigit, (=='_')]
[isAlpha, isDigit, (=='_')] :: [Char -> Bool]
Notice that this expression has the type [Char -> Bool]. It doesn't fit the or function.
In order to pass an appropriate argument to the filter function, you'll need to find a way to turn [Char -> Bool] into Char -> Bool. Do you need help with that?
After the considering #Mark Seemann guidance I decided to that i needed to create a function isIdChar :: Char -> Bool that tests if a Char fits the criteria of either being a letter , digit or underscore. I then used the function in my filter. That way the function returned Char -> Bool as #Mark Seemann suggested.
isIdChar :: Char -> Bool
isIdChar c = isAlpha c || isDigit c || c == '_'
isIdentifier :: String -> Bool
isIdentifier [] = False
isIdentifier (x:[]) = False
isIdentifier(x:xs)
| isAlpha x && length(filter isIdChar xs ) == length xs = True
| otherwise = False
Initially I used the || infix operator in my solution but I've also provided solution that uses the or function
isIdChar :: Char -> Bool
isIdChar c = or[isAlpha c, isDigit c , (c == '_')]
isIdentifier :: String -> Bool
isIdentifier [] = False
isIdentifier (x:[]) = False
isIdentifier(x:xs)
| isAlpha x && length(filter isIdChar xs ) == length xs = True
| otherwise = False
This is a great place to use the swing function! Just replace your or with swing any:
swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing f c a = f ($ a) c
isIdentifier :: String -> Bool
isIdentifier [] = False
isIdentifier (x:[]) = False
isIdentifier(x:xs)
| isAlpha x && length(filter(swing any [isAlpha, isDigit, (=='_')]) xs ) == length xs = True
| otherwise = False
You can also simplify your function a bit:
swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing f c a = f ($ a) c
isIdentifier :: String -> Bool
isIdentifier (x:xs#(_:_)) = isAlpha x && all (swing any [isAlpha, isDigit, (== '_')]) xs
isIdentifier _ = False

No instance for (Num Bool) arising from the literal ‘0’

My code:
divisibleBy :: Int -> Int -> Bool
divisibleBy x y
| mod x y == 0 = True
| otherwise = False
isEven :: Int -> Bool
isEven x
| (divisibleBy x 2) == 0 = True
| otherwise = False
Error:
practical1.hs:30:28: error:
• No instance for (Num Bool) arising from the literal ‘0’
• In the second argument of ‘(==)’, namely ‘0’
In the expression: (divisibleBy x 2) == 0
In a stmt of a pattern guard for
an equation for ‘isEven’:
(divisibleBy x 2) == 0
|
30 | | (divisibleBy x 2) == 0 = True |
The divisibleBy function works, but the isEven one doesn't. What am I doing wrong?
Well the error message already says this. You write:
isEven :: Int -> Bool
isEven x
| (divisibleBy x 2) == 0 = True
| otherwise = False
Now if we typecheck this, we see that (divisibleBy x 2) will return a Bool, and you cannot perform a (==) with a Bool and a number (a Bool is in Haskell not a number).
Why you write this with == 0 is not really clear for me, we can write it as:
isEven :: Int -> Bool
isEven x
| (divisibleBy x 2) = True
| otherwise = False
But now it is still inelegant: we do not have to check if a condition holds to return True and otherwise False, we can simply return the definition, so:
isEven :: Int -> Bool
isEven x = divisibleBy x 2
Or we can omit the x parameter, by using flip :: (a -> b -> c) -> b -> a -> c:
isEven :: Int -> Bool
isEven = flip divisibleBy 2
The same holds for the divisibleBy function, we can rewrite it to:
divisibleBy :: Int -> Int -> Bool
divisibleBy x y = mod x y == 0
Or without parameters:
divisibleBy :: Int -> Int -> Bool
divisibleBy = ((0 ==) .) . mod
Swapping the parameters of divisableBy
It looks however more Haskell to swap the parameters of the function, so we can write it as:
divisibleBy :: Int -> Int -> Bool
divisibleBy x y = mod y x == 0
Since now we can define a function divisibleBy 2, that will check for any parameter whether that number is divisible by two.
In that case, the isEven function, looks like:
isEven :: Int -> Bool
isEven = divisibleBy 2

Memoisation with auxiliary parameter in Haskell

I have a recursive function f that takes two parameters x and y. The function is uniquely determined by the first parameter; the second one merely makes things easier.
I now want to memoise that function w.r.t. it's first parameter while ignoring the second one. (I.e. f is evaluated at most one for every value of x)
What is the easiest way to do that? At the moment, I simply define an array containing all values recursively, but that is a somewhat ad-hoc solution. I would prefer some kind of memoisation combinator that I can just throw at my function.
EDIT: to clarify, the function f takes a pair of integers and a list. The first integer is some parameter value, the second one denotes the index of an element in some global list xs to consume.
To avoid indexing the list, I pass the partially consumed list to f as well, but obviously, the invariant is that if the first parameter is (m, n), the second one will always be drop n xs, so the result is uniquely determined by the first parameter.
Just using a memoisation combinator on the partially applied function will not work, since that will leave an unevaluated thunk \xs -> … lying around. I could probably wrap the two parameters in a datatype whose Eq instance ignores the second value (and similarly for other instances), but that seems like a very ad-hoc solution. Is there not an easier way?
EDIT2: The concrete function I want to memoise:
g :: [(Int, Int)] -> Int -> Int
g xs n = f 0 n
where f :: Int -> Int -> Int
f _ 0 = 0
f m n
| m == length xs = 0
| w > n = f (m + 1) n
| otherwise = maximum [f (m + 1) n, v + f (m + 1) (n - w)]
where (w, v) = xs !! m
To avoid the expensive indexing operation, I instead pass the partially-consumed list to f as well:
g' :: [(Int, Int)] -> Int -> Int
g' xs n = f xs 0 n
where f :: [(Int, Int)] -> Int -> Int -> Int
f [] _ _ = 0
f _ _ 0 = 0
f ((w,v) : xs) m n
| w > n = f xs (m + 1) n
| otherwise = maximum [f xs (m + 1) n, v + f xs (m + 1) (n - w)]
Memoisation of f w.r.t. the list parameter is, of course, unnecessary, since the list does not (morally) influence the result. I would therefore like the memoisation to simply ignore the list parameter.
Your function is unnecessarily complicated. You don't need the index m at all:
foo :: [(Int, Int)] -> Int -> Int
foo [] _ = 0
foo _ 0 = 0
foo ((w,v):xs) n
| w > n = foo xs n
| otherwise = foo xs n `max` foo xs (n - w) + v
Now if you want to memoize foo then both the arguments must be considered (as it should be).
We'll use the monadic memoization mixin method to memoize foo:
First, we create an uncurried version of foo (because we want to memoize both arguments):
foo' :: ([(Int, Int)], Int) -> Int
foo' ([], _) = 0
foo' (_, 0) = 0
foo' ((w,v):xs, n)
| w > n = foo' (xs, n)
| otherwise = foo' (xs, n) `max` foo' (xs, n - w) + v
Next, we monadify the function foo' (because we want to thread a memo table in the function):
foo' :: Monad m => ([(Int, Int)], Int) -> m Int
foo' ([], _) = return 0
foo' (_, 0) = return 0
foo' ((w,v):xs, n)
| w > n = foo' (xs, n)
| otherwise = do
a <- foo' (xs, n)
b <- foo' (xs, n - w)
return (a `max` b + v)
Then, we open the self-reference in foo' (because we want to call the memoized function):
type Endo a = a -> a
foo' :: Monad m => Endo (([(Int, Int)], Int) -> Int)
foo' _ ([], _) = return 0
foo' _ (_, 0) = return 0
foo' self ((w,v):xs, n)
| w > n = foo' (xs, n)
| otherwise = do
a <- self (xs, n)
b <- self (xs, n - w)
return (a `max` b + v)
We'll use the following memoization mixin to memoize our function foo':
type Dict a b m = (a -> m (Maybe b), a -> b -> m ())
memo :: Monad m => Dict a b m -> Endo (a -> m b)
memo (check, store) super a = do
b <- check a
case b of
Just b -> return b
Nothing -> do
b <- super a
store a b
return b
Our dictionary (memo table) will use the State monad and a Map data structure:
import Prelude hiding (lookup)
import Control.Monad.State
import Data.Map.Strict
mapDict :: Ord a => Dict a b (State (Map a b))
mapDict = (check, store) where
check a = gets (lookup a)
store a b = modify (insert a b)
Finally, we combine everything to create a memoized function memoFoo:
import Data.Function (fix)
type MapMemoized a b = a -> State (Map a b) b
memoFoo :: MapMemoized ([(Int, Int)], Int) Int
memoFoo = fix (memo mapDict . foo')
We can recover the original function foo as follows:
foo :: [(Int, Int)] -> Int -> Int
foo xs n = evalState (memoFoo (xs, n)) empty
Hope that helps.

Resources