Access constructor name and arguments - haskell

I'm going to override the equal class for Dynamic data type in this way:
instance Eq Dynamic where
x==y = dynamicEq x y
dynamicEq :: Dynamic -> Dynamic -> Bool
dynamicEq x y = ConstrName x == ConstrName y && sameSlots(slots x)(slots y)
where
sameSlots [] [] = True
sameSlots ((x::Eq a => a):xs)(y:ys) = x == fromDynamic y && sameSlots xs ys
can you name or declare any function that can return the values of ConstrName and slots for me? Maybe using Tycon or something similar?

Never fiddled with this stuff, but here may be two partial answers which could be enough for you. I'm afraid it's not a general solution nor a way to make Dynamic and instance of Eq (it would probably be one already if it was easy).
But in your last comment you stated that you only wanted to compare your own types. So, partial answer 1:
You can of course compare two Dynamics if you guess their type. For example:
eqInt :: Int -> Int -> Bool
eqInt = (==)
x = toDyn (3::Int)
y = toDyn (3::Int)
z = toDyn (4::Int)
compareDynamic :: (Typeable a, Eq a) =>
(a -> a -> Bool) ->
Dynamic -> Dynamic -> Maybe Bool
compareDynamic eq x y = do
let dEq = toDyn eq
fn1 <- dynApply dEq x
res <- dynApply fn1 y
fromDynamic res
And now:
...> compareDynamic eqInt x y
Just True
...> compareDynamic eqInt x z
Just False
However, despite the misleading polymorphic type of compareDynamic, you can only pass in a monomorphic comparison function. See:
...> compareDynamic (==) x z
Nothing
I suppose that is because the type system has no way of knowing which instance of (==) it should actually use here. I kept compareDynamic polymorphic though so you don't have to create separate functions for each type.
Now, since you only want to compare your own types, you could just have a list of comparison functions which you try in order:
eqs = [eqMyTypeA, eqMyTypeB, eqMyTypeC]
comp dynA dynB = catMaybes $ map (\eq -> eq dynA dynB) eqs
And [] would denote two different types, [Just False] the same type with different values and [Just True] the same type and value.
In case you have a large number of types, you can also determine the constructor before doing any comparison, (this is partial answer 2) and select the right function depending on it. It the constructors are different, you wouldn't have to try compare at all:
constructor :: Dynamic -> TyCon
constructor = typeRepTyCon . dynTypeRep
And have a lookup table matching constructors to equality functions.
One closing remark: Think twice if you need this. Think thrice if you need Dynamic at all, most Haskell programs don't. Isn't it just Java thinking sneaking in?

Related

Haskell parameters - comparison operators

I'd like to define a function whose parameter takes in a list and an operator. This is what I currently have. I'm trying to define a higher order function that can find the minimum or the maximum.
largest :: (a -> a -> Bool) -> a
largest = findType (>)
findType :: (a -> a -> Bool) -> [a] -> a
findType op [] = error "empty list"
findType op [x] = x
findType op (x:xs)
| x op maxTail = x
| otherwise = maxTail
where maxTail = findType op xs
However, it's not currently working.
You can either write a function that accepts any a -> a -> Bool function parameter, or use the fact that comparable data types implement Ord class.
Here is a piece of code showing both methods to check if a list is sorted
option1 :: (a->a->Bool) -> [a] -> Bool
option1 op (a:b:ls) = op a b && option1 op (b:ls)
option1 op _ = True
option2 :: (Ord a) => Ordering -> [a] -> Bool
option2 op (a:b:ls) = compare a b == op && option2 op (b:ls)
option2 op _ = True
main = do
let ls = [1, 2, 3]
print $ option1 (<) ls
print $ option2 LT ls
Note that the 2nd method requires the use of Ordering data type which only has values LT, EQ and GT (meaning <, = and > respectively). You could make it more flexible by passing, say, a list of acceptable Ordering values or some other data structure, however, in most cases 1st option is more appropriate.
Your code as two different problems. Let's address the one generating the compiler error first.
You gave to findType the following signature:
findType :: (a -> a -> Bool) -> [a] -> a
the intent being to extract from the list given as the second parameter the bound as dictated by the ordering predicate provided as the first parameter.
However, in the last line of the very findType function definition, you bind maxTail to the expression findType xs, which omits the predicate.
The correct line is of course:
where maxTail = findType op xs
Your second error is related to the signature of the largest function, but I will let you find out exactly what it is.
GHC doesn't know that you want to use the function op as an operator into your code, you must tell him, but how can you do that ?
Let's consider the elem function, this function take a value and a list and return True or False depending if the value is present into the list or not.
elem :: Eq a => a -> [a] -> Bool
elem 2 [1,2,3] => True
Basically it's see as a function, and if you want to use them as an operator which can be really useful, you must enclose it with `.
2 `elem` [1,2,3] => True
If you add the remarks of didierc on the call of findType into the where clause, you'll have a working code.
Anyway, It's a very bad idea to put a recursive call into a guard, the code is hardest to read, and I'm not sure be it could lead to performance issue. You need to learn how to use an accumulator, take a look on this
Note
Conversely when a function is considered by default as an operator, to use it as a function just enclose it with ().
2 : [] => [2]
(:) 2 [] => [2]

How to use higher order functions effectively?

By utilizing higher order functions, what is the best way to implement the function makeCloths?
What I'm hoping to achieve is that makeCloths can automatically populate each method in the methodsList with the correct arguments that is provided in the materialList. So that in the future if more methods are added to the methodsList, and the methods uses only the arguments in materialList, we don't need to modify the code in makeCloths.
data Material = WhiteCloth Int
| BlueCloth Int
| RedCloth Int
makeWhiteShirt :: Material -> Clothe
makeWhiteShirt (WhiteCloth x) = .....
makeBluePants :: Material -> Clothe
makeBluePants (BlueCloth x) = .....
makeRedBlueDress :: Material -> Material -> Clothe
makeRedBlueDress (RedCloth x) (BlueCloth y) = ......
methodsList = [ makeWhiteShirt, makeBluePants, makeRedBlueDress ]
materialList = [ WhiteCloth 3, BlueCloth 2, RedCloth 2]
-- call makeCloths like so
-- listOfClothes = makeCloths methodsList materialList
makeCloths :: [a] -> [b] -> [Clothe]
First off, as many others have suggested, haskell wouldn't allow you to have an array of functions whose cardinality don't match. You would want to make makeRedBlueDress to be of type Material -> Clothe. If you really want this kind of polymorphism, nothing stops us from defining additional type for Material that takes multiple arguments (or composed of multiple Materials)
Once we have that, makeCloths is a special case of zipWith function.
makeCloths = zipWith $ \x y -> (x y)
The type signature for it makes the most sense
zipWith $ \x y -> (x y) :: [b -> c] -> [b] -> [c]

How can I iterate over a string without recursion?

isTogether' :: String -> Bool
isTogether' (x:xs) = isTogether (head xs) (head (tail xs))
For the above code, I want to go through every character in the string. I am not allowed to use recursion.
isTogether' (x:xs) = isTogether (head xs) (head (tail xs))
If I've got it right, you are interested in getting consequential char pairs from some string. So, for example, for abcd you need to test (a,b), (b,c), (c,d) with some (Char,Char) -> Bool or Char -> Char -> Bool function.
Zip could be helpful here:
> let x = "abcd"
> let pairs = zip x (tail x)
it :: [(Char, Char)]
And for some f :: Char -> Char -> Bool function we can get uncurry f :: (Char, Char) -> Bool.
And then it's easy to get [Bool] value of results with map (uncurry f) pairs :: [Bool].
In Haskell, a String is just a list of characters ([Char]). Thus, all of the normal higher-order list functions like map work on strings. So you can use whichever higher-order function is most applicable to your problem.
Note that these functions themselves are defined recursively; in fact, there is no way to go through the entire list in Haskell without either recursing explicitly or using a function that directly or indirectly recurses.
To do this without recursion, you will need to use a higher order function or a list comprehension. I don't understand what you're trying to accomplish so I can only give generic advice. You probably will want one of these:
map :: (a -> b) -> [a] -> [b]
Map converts a list of one type into another. Using map lets you perform the same action on every element of the list, given a function that operates on the kinds of things you have in the list.
filter :: (a -> Bool) -> [a] -> [a]
Filter takes a list and a predicate, and gives you a new list with only the elements that satisfy the predicate. Just with these two tools, you can do some pretty interesting things:
import Data.Char
map toUpper (filter isLower "A quick test") -- => "QUICKTEST"
Then you have folds of various sorts. A fold is really a generic higher order function for doing recursion on some type, so using it takes a bit of getting used to, but you can accomplish pretty much any recursive function on a list with a fold instead. The basic type of foldr looks like this:
foldr :: (a -> b -> b) -> b -> [a] -> b
It takes three arguments: an inductive step, a base case and a value you want to fold. Or, in less mathematical terms, you could think of it as taking an initial state, a function to take the next item and the previous state to produce the next state, and the list of values. It then returns the final state it arrived at. You can do some pretty surprising things with fold, but let's say you want to detect if a list has a run of two or more of the same item. This would be hard to express with map and filter (impossible?), but it's easy with recursion:
hasTwins :: (Eq a) => [a] -> Bool
hasTwins (x:y:xs) | x == y = True
hasTwins (x:y:xs) | otherwise = hasTwins (y:xs)
hasTwins _ = False
Well, you can express this with a fold like so:
hasTwins :: (Eq a) => [a] -> Bool
hasTwins (x:xs) = snd $ foldr step (x, False) xs
where
step x (prev, seenTwins) = (x, prev == x || seenTwins)
So my "state" in this fold is the previous value and whether we've already seen a pair of identical values. The function has no explicit recursion, but my step function passes the current x value along to the next invocation through the state as the previous value. But you don't have to be happy with the last state you have; this function takes the second value out of the state and returns that as the overall return value—which is the boolean whether or not we've seen two identical values next to each other.

Getting minimum values of mappings

I want to get the minimum values from two mappings and subtract one from the other. I'm really new to Haskell and am pretty embarrassed by my attempt but I wanted to give it a go before asking!
calc :: (a -> b) -> [a] -> Float
calc = a - b
where
a = minimum map1
b = minimum map2
map1 f xs = [f x | x <- xs]
map2 f xs = [square x | x <- xs]
square x = x*x
I'm getting so many errors that I feel like I must be doing it completely the wrong way?
The first problem is that map2 just discards the function it's given. map1 is just the standard map function, so you don't need to define it. map2 can be defined properly as:
map2 = map square
The second problem is that you haven't supplied map1 and map2 with any arguments in your definition of calc. Is something like this what you want?
calc :: (a -> b) -> [a] -> Float
calc f xs = a - b
where
a = minimum (map f xs)
b = minimum (map2 xs)
Basically, your problem is that you're declaring parameters but not processing them, or using functions that take parameters without actually specifying them. That doesn't work in any language :)
That's not all, however. Your type for calc is wrong. I suggest you think about why this can't work — in particular, what if I say a is String and b is ()? You can try removing the type signature of calc and entering :t calc into GHCi to find out what the type GHC infers for calc is to get a head-start on correcting it.

Number of elements in list bigger than average

I'm trying to write a program in Haskell
that gets a list (of integer) and prints out the number of elements that are bigger than the list's average
So far I tried
getAVG::[Integer]->Double
getAVG x = (fromIntegral (sum x)) / (fromIntegral (length x))
smallerThanAVG:: [Integer]->Integer
smallerThanAVG x = (map (\y -> (if (getAVG x > y) then 1 else 0)) x)
For some reason I'm getting this error
Couldn't match expected type `Double'
against inferred type `Integer'
Expected type: [Double]
Inferred type: [Integer]
In the second argument of `map', namely `x'
It could be that I haven't written the logic correctly, although I think I did..
Ideas?
These errors are the best kind, because they pinpoint where you have made a type error.
So let's do some manual type inference. Let's consider the expression:
map (\y -> (if (getAvg x > y) then 1 else 0)) x
There are a few constraints we know off the bat:
map :: (a -> b) -> [a] -> [b] -- from definition
(>) :: Num a => a -> a -> Bool -- from definition
getAvg :: [Integer] -> Double -- from type declaration
1, 0 :: Num a => a -- that's how Haskell works
x :: [Integer] -- from type declaration of smallerThanAVG
Now let's look at the larger expressions.
expr1 = getAvg x
expr2 = (expr1 > y)
expr3 = (if expr2 then 1 else 0)
expr4 = (\y -> expr3)
expr5 = map expr4 x
Now let's work backwards. expr5 is the same as the RHS of smallerThanAVG, so that means it has the same result type as what you've declared.
expr5 :: Integer -- wrong
However, this doesn't match our other constraint: the result of map must be [b] for some b. Integer is definitely not a list (although if you get facetious, it could be coerced into a list of bits). You probably meant to sum that list up.
expr6 = sum expr5
sum :: Num a => [a] -> a
Now let's work forwards.
expr1 :: Double -- result type of getAvg
y :: Double -- (>) in expr2 requires both inputs to have the same type
expr4 :: (Integer -> [a]) -- because for `map foo xs` (expr5)
-- where xs :: [a], foo must accept input a
y :: Integer -- y must have the input type of expr4
Herein lies the conflict: y cannot be both a Double and an Integer. I could equivalently restate this as: x cannot be both a [Double] and [Integer], which is what the compiler is saying. So tl;dr, the kicker is that (>) doesn't compare different types of Nums. The meme for this sort of problem is: "needs more fromIntegral".
(getAvg x > fromIntegral y)
Your code has two errors.
Although the type signature in the code declares that smallerThanAVG x evaluates to an Integer, its code is map ... x, which clearly evaluates to a list instead of a single Integer.
In the code getAVG x > y, you are comparing a Double to an Integer. In Haskell, you can only compare two values of the same type. Therefore, you have to use fromIntegral (or fromInteger) to convert an Integer to a Double. (This is essentially what caused the error message in the question, but you have to get used to it to figure it out.)
There are several ways to fix item 1 above, and I will not write them (because doing so would take away all the fun). However, if I am not mistaken, the code you are aiming at seems like counting the number of elements that are smaller than the average, in spite of what you write before the code.
Styling tips:
You have many superfluous parentheses in your code. For example, you do not have to parenthesize the condition in an if expression in Haskell (unlike if statement in C or Java). If you want to enjoy Haskell, you should learn Haskell in a good style instead of the Haskell which just works.
You call the variable which represents a list “x” in your code. It is conventional to use a variable name such as xs to represent a list.
Others have explained the errors beautifully.
I'm still learning Haskell but I'd like to provide an alternative version of this function:
greaterThanAvg :: [Int] -> [Int]
greaterThanAvg xs = filter (>avg) xs
where avg = sum xs `div` length xs
cnt = length $ greaterThanAvg [1,2,3,4,5]

Resources