I have started this a new question as it became a follow-on from my previous question.
If I have two data types which are composed of similar constructors:
data A = X | Y | Z
data B = X | Y
is there no way I can somehow represent this as:
data A = C | Z
data B = C
data C = X | Y
if you can see what I am doing- I am trying to group the X | Y into one data type, which can then be used by multiple other data types. I cannot seem to get the compiler to allow this, or if it does, I cannot pattern-match against the X or Y, only the C??
I get the error message that C has been declared multiple times.
I thought I could maybe use types, but they do not allow multiple typings.
EDIT
Even if I declare the long way (like below), it still won't compile and says X and Y have multiple declarations:
data A = X | Y | Z
data B = X | Y
Not only can't you do this, you also can't do your first option - i.e. you can't have two types in the same module that both have constructors named X and Y.
If you could do this, what should the type of X be - C, A or B? The most obvious answer would be C, but then you wouldn't be able to use it in a context where an A or a B are required (note that Haskell has no subtyping), so that would defeat the purpose of the whole construct.
The best you can do is to wrap C in a constructor of A and B, i.e.:
data A = AC C | Z
data B = BC C
data C = X | Y
Then you could wrap a C with either the AC or the BC constructor to create a value of type A or B respectively.
The reason you can't do this
data A = X | Y | Z
data B = X | Y
is as follows. Say you write some code later on:
foo n = (n,X)
which builds a pair consisting of n in the first slot and X in the second slot. What type should the compiler infer? A valid type would be
foo :: a -> A -> (a,A)
since X is a constructor of type A, but equally valid is
foo :: a -> B -> (a,B)
since X is a constructor of type B. If you have two constructors with the same name, you can't infer a unique type for functions that use them. So you are disallowed from giving two constructors in the same module the same name.
You can't do this:
data A = C | Z
data B = C
data C = X | Y
(As an aside, if B is identical to C, then why have B at all?)
But what you can do is something like this:
data A = A_Other C | Z
data B = B_Other C
data C = X | Y
Then you can pattern match like this:
foo :: A -> String
foo (A_Other X) = "X"
foo (A_Other Y) = "Y"
foo ( Z) = "Z"
bar :: B -> String
bar (B_Other X) = "X"
bar (B_Other Y) = "Y"
foobar :: C -> String
foobar X = "X"
foobar Y = "Y"
If that makes sense...
You cannot do what you want because you are declaring multiple data constructors. In
data A = X | Y | Z
You are actually introducing the type A which has 3 constructors (values) X, Y, and Z. This is why your first piece of code won't compile, it sees the same name listed as constructors for two different types! If you could do this you'd have to ask yourself is
X :: A
or
X :: B
which in a non object-oriented context is scary! So you need to provide different constructor names to share that underlying data, C.
If you want to factor this, you can do as the other posts have suggested and factored-out data in unique constructors for each datatype
data A = CForA C | Z
data B = CForB C
data C = X | Y
Related
So, I have been trying to use SDL to make a simple GUI. This is so that I start to understand how to use haskell. In this case, I was using https://github.com/palf/haskell-sdl2-examples/blob/master/examples/lesson04/src/Lesson04.hs as reference.
Pay attention, in particular to payloadToIntent on line 72.
payloadToIntent :: SDL.EventPayload -> Intent
payloadToIntent SDL.QuitEvent = Quit
payloadToIntent (SDL.KeyboardEvent k) = getKey k
payloadToIntent _ = Idle
This works perfectly. However, when I change the code to the following, it produces an error. Why does it happen, as to my (admittedtly novice) eyes, this looks equivalent.
payloadToIntent e
| e == SDL.QuitEvent = Quit
| e == SDL.KeyboardEvent k = getKey SDL.KeyboardEvent k
| otherwise = Idle
Error:
src/Events/Intent.hs:15:28: error:
Variable not in scope: k :: SDL.KeyboardEventData
|
15 | | e == SDL.KeyboardEvent k = getKey SDL.KeyboardEvent
| ^
I am using these language extensions: OverloadedStrings, GADTs, PatternGuards
So why did this happen? How could I fix this? Which one would be more idiomatic haskell?
(==) is a function that takes two values of the same type and compares them for equality, returning a Bool. SDL.KeyboardEvent k is not a value of any type (since k is unbound), so you can't compare it with (==).
The idiomatic "choice" is the one that works, i.e. pattern matching. If you want something that has a similar appearance, you can pattern match with case...of instead:
payloadToIntent e = case e of
SDL.QuitEvent -> Quit
SDL.KeyboardEvent k -> getKey k
_ -> Idle
The key idea here is: patterns define variables, bringing them into scope, while expressions do not, requiring all the variables in them to be already defined.
The guard e == SDL.KeyboardEvent k is a boolean valued expression, not a pattern. This is calling function (==) with two arguments: e and SDL.KeyboardEvent k. Your definition, to the compiler, looks like:
payloadToIntent e
| isEqual e SDL.QuitEvent = Quit
| isEqual e (SDL.KeyboardEvent k) = getKey SDL.KeyboardEvent k
| otherwise = Idle
The compiler can not call the equality-test function without passing it the arguments. For that, it needs variable k to be in scope, i.e., to be defined somewhere else.
To stress the point, consider this non-working code:
isSquare :: Int -> String
isSquare n | n == m*m = "It's the square of " ++ show m
| otherwise = "It isn't a square"
This would magically invert the squaring, if possible. That is, however, asking too much to the compiler, which won't magically solve the equation for us. (Indeed, the solution could even fail to be unique!)
As an even more cumbersome case:
f x | x == F y || x == G z = ...
Even if this worked, can we use y or z in the final ...? Probably not. Why should then this be allowed?
Finally, note that, even in those cases where it could work, allowing expressions guards to define variables could be a bad idea. Consider this:
c :: Int
c = 7
f x | x == F c = "Hi"
| otherwise = "there"
Now, is the c in F c a new local variable which is defined on the spot, or is it the constant 7 defined above? If we call f (F 6) do we get Hi (c was a new variable) or there (c was 7)?
Pattern matching avoids this issue by requiring a distinct syntax.
I need to write a function that makes the same job as [a..b] by using the : operator and guards.
is it possible to do it? where should I begin?
list a b
| a < b = print[a..b]
| otherwise = print[a,a-1..b]
You can try deriving it from the laws it must follow, i.e.
list a b | a > b = []
list a b | a <= b = [a..b]
= a : [(a+1)..b]
But then we can read the last equation right to left to get
[(a+1)..b] = list (a+1) b
and substituting it back into the last law gives us the definition that we needed.
update: so looks like what you really wanted is to count up or down depending on the relation between a and b. This just needs some tweaking:
list a b | a == b = [a]
list a b | a < b = [a..b]
= a : [(a+1)..b]
= a : list (a+1) b
list a b | a > b = [a,a-1..b]
= a : [a-1,a-2..b]
= a : list (a-1) b
This will perform some redundant checks while counting. These can be avoided by defining two specialized internal functions for the counting up or down, and using those after the initial checks.
Is it better to compare with the parent function or within the same function? #Will Ness
list a b| a < b = greaterB a b
list a b| a >= b = greaterA a b
greaterB a b
| a > b = []
| a <= b = a:greaterB(a+1) b
greaterA a b
| a >= b = a:greaterA(a-1) b
| a < b = []
If I have a function, for example
f :: Int -> Int -> Int
f x y = x + y
and I want to have different functionality based on the parameters, I use pattern matching.
I have only found the syntax of how to match against concrete values, e.g.
f 0 y = y
Is it possible to match against something more general?
I would like to have different functionality in the case that the first parameter is less than 0. A second case could be if the second parameter exceeds a certain value.
You can use guards:
f x y | x < 0 = ...
f x y | y > someValue = ...
f x y | otherwise = ...
Sure, there is a mechanism called guards for that:
f x y | x < 0 = y
I'm still trying to grasp an intuition of pullbacks (from category theory), limits, and universal properties, and I'm not quite catching their usefulness, so maybe you could help shed some insight on that as well as verifying my trivial example?
The following is intentionally verbose, the pullback should be (p, p1, p2), and (q, q1, q2) is one example of a non-universal object to "test" the pullback against to see if things commute properly.
-- MY DIAGRAM, A -> B <- C
type A = Int
type C = Bool
type B = (A, C)
f :: A -> B
f x = (x, True)
g :: C -> B
g x = (1, x)
-- PULLBACK, (p, p1, p2)
type PL = Int
type PR = Bool
type P = (PL, PR)
p = (1, True) :: P
p1 = fst
p2 = snd
-- (g . p2) p == (f . p1) p
-- TEST CASE
type QL = Int
type QR = Bool
type Q = (QL, QR)
q = (152, False) :: Q
q1 :: Q -> A
q1 = ((+) 1) . fst
q2 :: Q -> C
q2 = ((||) True) . snd
u :: Q -> P
u (_, _) = (1, True)
-- (p2 . u == q2) && (p1 . u = q1)
I was just trying to come up with an example that fit the definition, but it doesn't seem particularly useful. When would I "look for" a pull back, or use one?
I'm not sure Haskell functions are the best context
in which to talk about pull-backs.
The pull-back of A -> B and C -> B can be identified with a subset of A x C,
and subset relationships are not directly expressible in Haskell's
type system. In your specific example the pull-back would be
the single element (1, True) because x = 1 and b = True are
the only values for which f(x) = g(b).
Some good "practical" examples of pull-backs may be found
starting on page 41 of Category Theory for Scientists
by David I. Spivak.
Relational joins are the archetypal example of pull-backs
which occur in computer science. The query:
SELECT ...
FROM A, B
WHERE A.x = B.y
selects pairs of rows (a,b) where a is a row from table A
and b is a row from table B and where some function of a
equals some other function of b. In this case the functions
being pulled back are f(a) = a.x and g(b) = b.y.
Another interesting example of a pullback is type unification in type inference. You get type constraints from several places where a variable is used, and you want to find the tightest unifying constraint. I mention this example in my blog.
Just staring with Haskell. I want to define some elements to easily create morphisms between them.
a = "foo"
b = "bar"
g a = a --Problem is here
g b = a --Problem is here
Edit The problem is that haskell treats "a" in "g a" as a variable, but I actually want the value of the "a" defined above. Conceptually a want this
g (valueOf a) = a --Problem is here
g (valueOf b) = a --Problem is here
Where valueOf is a magic function that would give me
g "foo" = a
g "bar" = a
Use
a = "foo"
b = "bar"
g x | x==a = a
| x==b = a
or
g "foo" = a
g "bar" = a
When you pattern match using a variable as in
g a = ...
the variable a is a local variable, bound to the argument of the function. Even if a was already defined globally, the code above will not use the value of the global a to perform a comparison.
This semantics allows to reason locally about your code. Consider this code as an example:
f 2 x = 4
f c d = 0
Just by looking at the above definition you can see that f 2 3 is 4. This is not changed if later on you add a definition for x as follows:
x = 5
f 2 x = 4
f c d = 0
If the match semantics compared the second argument to 5, now we would have f 2 3 equal to 0. This would make reasoning about the function definitions harder, so most (if not all) functional languages such as Haskell use "local" variables for pattern matching, ignoring the possible global definitions for such variables.
A more adventurous alternative is to use view patterns:
{-# LANGUAGE ViewPatterns #-}
a = "foo"
b = "bar"
g ((==a) -> True) = ...
g ((==b) -> True) = ...
I am not a fan of this approach though, since I find standard patterns with guards to be clearer.
Apologies in advance if this is a complete misunderstanding of what
you want to accomplish but wouldn't something like this do?
Data Obj = A | B
g A = A
g B = A
f A = "foo"
f B = "bar"
You want a predefined set of objects, yes?