How to check if a variable has been constructed with a constructor? - constructor

Given
type Bla = A Int | B Int
valA1 = A 1
valA2 = A 2
is there a way for me to check whether valA1 has been constructed with the constructor of valA2?

There is no general purpose way of comparing constructors but you could put together your own function easily:
isSameBlaConstructor : Bla -> Bla -> Bool
isSameBlaConstructor x y =
case (x, y) of
(A _, A _) -> True
(B _, B _) -> True
_ -> False

Related

Abstracting Function in Haskell

I am currently taking a class in Haskell and am having a bit of trouble understanding how functions are passed as parameters. For this assignment, we were tasked with creating a program that would evaluate expressions. To reduce boiler plating, I wanted to abstract the function by creating a helper function that would take in an operator as an input and return the result
Main Function:
eval :: EDict -> Expr -> Maybe Double
eval _ (Val x) = Just x
eval d (Var i) = find d i
eval d (Add x y) = evalOp d (+) x y
eval d (Mul x y) = evalOp d (*) x y
eval d (Sub x y) = evalOp d (-) x y
Helper Function:
evalOp:: EDict -> ((Num a) => a -> a -> a) -> Expr -> Expr -> Maybe Double
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
Other definitions
data Expr
= Val Double
| Add Expr Expr
| Mul Expr Expr
| Sub Expr Expr
| Dvd Expr Expr
| Var Id
| Def Id Expr Expr
deriving (Eq, Show)
type Dict k d = [(k,d)]
define :: Dict k d -> k -> d -> Dict k d
define d s v = (s,v):d
find :: Eq k => Dict k d -> k -> Maybe d
find [] _ = Nothing
find ( (s,v) : ds ) name | name == s = Just v
| otherwise = find ds name
type EDict = Dict String Double
I looked into how +,-, and * are to be passed into other functions and found that these operators are defined by the following definition:
ghci> :t (*)
(*) :: (Num a) => a -> a -> a
However, when I run my code I get the following compilation error:
Illegal polymorphic or qualified type: Num a => a -> a -> a
Perhaps you intended to use RankNTypes or Rank2Types
In the type signature for ‘evalOp’:
evalOp :: EDict
-> ((Num a) => a -> a -> a) -> Expr -> Expr -> Maybe Double
I am not really sure why this is happening as I gave my function the proper parameters as defined by Haskell. Any help would be greatly appreciated as I am still very new to the language.
Right now, your Expr data type is constrained to Double-valued expressions, so there is no need to deal with polymorphism.
evalOp:: EDict -> (Double -> Double -> Double) -> Expr -> Expr -> Maybe Double
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
(+) :: Num a => a -> a -> a is a valid argument for evalOp, because its type can be "restricted" to Double -> Double -> Double.
> let f :: Double -> Double -> Double; f = (+)
> f 3 5
8.0
If your expression type were parameterized, then you would put a Num a constraint on your functions (not just on the arguments that involve a, because you want the same a throughout the function).
data Expr a
= Val a
| Add (Expr a) (Expr a)
| Mul (Expr a) (Expr a)
| Sub (Expr a) (Expr a)
| Dvd (Expr a) (Expr a)
| Var Id
| Def Id (Expr a) (Expr a)
deriving (Eq, Show)
type EDict a = Dict String a
evalOp:: Num a => EDict a -> (a -> a -> a) -> Expr a -> Expr a -> Maybe a
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
eval :: Num a => EDict a -> Expr a -> Maybe a
eval _ (Val x) = Just x
eval d (Var i) = find d i
eval d (Add x y) = evalOp d (+) x y
eval d (Mul x y) = evalOp d (*) x y
eval d (Sub x y) = evalOp d (-) x y
The error is telling you that you cannot nest a type qualifier inside one of the types in your function chain. Instead, put all of the qualifiers at the beginning of the type signature:
evalOp:: (Num a) => EDict -> (a -> a -> a) -> Expr -> Expr -> Maybe Double
See Haskell - Illegal Polymorphic type? for a more thorough discussion.

How to merge two functions into one in Haskell

I want to merge two functions into one.
The functions are
data Dice = Stone Char deriving (Show, Eq)
calculateScore :: [Dobbelsteen] -> Int
calculateScore xs = sum[giveValueDice x | x <- xs]
giveValueDice :: Dice -> Int
giveValueDice (Stone d) = if d == 'W' then 5 else digitToInt d
Normally, I would just copy one line into the first function en change a little bit to make the syntax correct. But here I am kinda lost how to do this
As you've already noticed, you can't just directly inline here; the reason for this is that you're pattern matching on Stone in giveValueDice. This pattern matching can be moved inside the right side of the list comprehension:
calculateScore :: [Dobbelsteen] -> Int
calculateScore xs = sum[if d == 'W' then 5 else digitToInt d | (Stone d) <- xs]
Another method for merging these two functions is using a where clause, which 'merges' one function into another while keeping them distince:
calculateScore :: [Dobbelsteen] -> Int
calculateScore xs = sum[giveValueDice x | x <- xs]
where
giveValueDice :: Dice -> Int
giveValueDice (Stone d) = if d == 'W' then 5 else digitToInt d

Haskell, how to check for a palindrom

I have a small question. How could I extend my function to return True even if a character is a capital letter or not.
My function works for Strings in lists:
f1 w = w == reverse w
Test:
*Main> let test = ["Boob"]
*Main> f1 test
True
*Main> let test2 = "Boob"
*Main> f1 test2
False
regards,
martin
what about
import Data.Char (toLower)
f1 :: String -> Bool
f1 w = w == reverse w
f2 :: String -> Bool
f2 str = f1 $ map toLower str
but what I would suggest is using good names for your functions
testPalindrome = f1
ignoreCase = map toLower
then
testPalindrome' = testPalindrome . ignoreCase
Update:
The . is concatenation of functions:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(g . f) x = g (f x)
f
A -----> B
\ |
\ |
g.f \ |g
\ |
V V
C
Update2
#dfeuer mentioned in the comments a very elegant solution
import Data.Function (on)
import Data.Char (toLower)
(=~=) :: String -> String -> Bool
-- | Equivalence of Strings, by ignoring the case
(=~=) = (==) `on` toLower
testPalindrome :: String -> Bool
testPalindrome w = w =~= reverse w
The function on (used infix with backtick syntax) takes a function (==) and a "modifier-function" toLower and applies it to the arguments of that function.
(f `on` g) x y = f (g x) (g y)
this is especially useful with binary operators like (==), (<) and so on.

Lifting a function with another function as an argument in Haskell

So I have a function in Haskell that I've simplified for the purpose of asking this question:
import Data.Foldable
import Data.Set
myFn :: Int -> Set Int
myFn a
| a <= 0 = singleton 1
| otherwise = foldMap helper (myFn (a - 1))
helper :: Int -> Set Int
helper a = insert (a + 2) (singleton a)
main :: IO ()
main = print . Data.Set.toList $ myFn 5
I want to have myFn's dependency on helper to be put into a Reader, since inversion of control allows me to switch implementations in my tests:
import Control.Monad.Reader
import Data.Foldable
import Data.Set
data MyEnv = MyEnv { helper' :: Int -> Set Int }
type MyReader = Reader MyEnv
myFn :: Int -> MyReader (Set Int)
myFn a
| a <= 0 = return $ singleton 1
| otherwise = do
myFn' <- myFn (a - 1)
helper'' <- asks helper'
return (foldMap helper'' myFn')
helper :: Int -> Set Int
helper a = insert (a + 2) (singleton a)
main :: IO ()
main =
let
myEnv = MyEnv helper
in
print . Data.Set.toList $ runReader (myFn 5) myEnv
This works fine, except I don't like these three lines in particular:
myFn' <- myFn (a - 1)
helper'' <- asks helper'
return (foldMap helper'' myFn')
I feel like there should be a way to lift foldMap in the same way as mapM is a lifted version of map through its composition with sequence. Ideally, I would like those three lines to collapse down to one:
foldMapM helper'' (partitions (n - 1))
Assuming that: helper'' :: Int -> MyReader (Set Int)
This would of course require a foldMapM function with a signature similar to:
foldMapM
:: (Monad m, Foldable t, Monoid n)
=> (a -> m n)
-> m (t a)
-> m n
I have tried so many things, but I just cannot seem to implement this function, though! Can anyone help?
Basically, you would like to create Monad m => m a -> m b -> m c from a -> b -> c. That's exactly what liftM2 (from Control.Monad) does:
liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
Promote a function to a monad, scanning the monadic arguments from
left to right. For example,
liftM2 (+) [0,1] [0,2] = [0,2,1,3]
liftM2 (+) (Just 1) Nothing = Nothing
Therefore, it's as simple as using liftM2 foldMap:
myFn :: Int -> MyReader (Set Int)
myFn a
| a <= 0 = return $ singleton 1
| otherwise = liftM2 foldMap (asks helper') (myFn (a - 1))
Alternatively you can use <$> and <*> from Control.Applicative if you don't like additional parentheses:
myFn :: Int -> MyReader (Set Int)
myFn a
| a <= 0 = return $ singleton 1
| otherwise = foldMap <$> asks helper' <*> myFn (a - 1)
For more information, have a look at the Typeclassopedia.

The type signature for `isprime' lacks an accompanying binding

I have this code:
esprimo :: Int->Bool
esPrimo x = if length (div x x) == 2 then True else False
But I pulled the error is above
In addition to what sibi said, I think what you are trying to do is this:
isPrime :: Int -> Bool
isPrime x = if length [d | d <- [1..x], x `mod` d == 0] == 2 then True else False
this is basically the direct translation of the mathematical concept of beeing prime into Haskell.
As you don't need the if as it checks the same == already returns a bit more readable might be:
isPrime :: Int -> Bool
isPrime x = length divisors == 2
where divisors = [d | d <- [1..x], x `isMultipleOf` d]
isMultipleOf m n = m `mod` n == 0
Please note that this is of course not the most performant prime-test.
The exact reason for your error is because of the different cases you have used in the type signature and the type definition:
esprimo :: Int -> Bool -- p should be capital here to work.
esPrimo x = if length (div x x) == 2 then True else False
Haskell is case sensitive, so esprimo and esPrimo are different. That being said there is other type error in your code: the type of div is div :: Integral a => a -> a -> a, so it returns a and you are applying length function on it. But length function only accepts list i.e [a] and not a which will produce you type error.