Pattern matching on a Haskell function with type variable - haskell

In Haskell, is it possible to pattern match on functions that have a type variable for the outer but not inner type? Here, for example, funky takes any type constructor that takes a Bar. While this works for destructuring the two cases, I'm not sure how to write the global case on the bottom, which should ideally return the result of the destructuring. I've put a question mark before q because that's what's stumping me - I'm not sure how to destructure that last pattern match to get the Bar out. Thanks in advance for your help!
data Bar = Bar
data Foo = AA Bar | BB Bar | CC Bar | DD Bar
funky :: x Bar -> Bar
funky (AA z) = z
funky (BB z) = z
funky (? q) = q

You can’t pattern-match on a function with a type variable on the outside. To see why, let’s look at your code:
data Bar = Bar
data Foo = AA Bar | BB Bar | CC Bar | DD Bar
funky :: x Bar -> Bar
The type signature for funky states that it takes a value of type x Bar and returns a value of type Bar. Importantly, it can do this for any type x of the appropriate kind — that’s what a type variable means.
Now, to see the problem with this, consider this type:
data Ignore a = Ignored
That is, for any type a, there is only one value of type Ignore a, and that value is Ignored.
So using this type, if we take x ~ Ignore, then funky becomes funky :: Ignore Bar -> Bar. The problem here should be obvious: there is no value of type Bar stored in Ignore Bar! So there’s no way to pattern-match on Ignore Bar and get out a Bar. And hence there is no way in general to write a function funky :: x Bar -> Bar which does what you want.

Related

Apply function to argument before performing pattern matching

I'm new to Haskell and trying to not instinctively think imperatively. I have a function which does all the work in a pattern matching block, however it needs to pattern match on the argument after a function is applied to it.
Doing this in a functional way gets me to this:
foo :: Int -> String
foo n = bar $ show n
bar :: String -> String
bar [] = ""
bar (c:s) = "-" ++ bar s
Where foo is the function I'm trying to implement but bar is where all the work gets done. foo only exists to provide the right type signature and perform the precursor show transformation before calling bar. In practice, bar could get quite complicated, but still, I have no reason to expose it as a separate function.
What's the Haskell way to perform a simple function like show and "then" pattern match on the result of that?
I tried changing the pattern matching to a case statement, but it didn't permit the all-important recursion, because there was no function to call recursively. For the same reason, using a where clause applied to multiple patterns also doesn't work.
I remembered that Learn You A Haskell often seemed to emphasise that where and let are more powerful than they first seem because "everything is a function" and the clauses are expressions themselves.
That prompted me to see if I could push where a bit harder and use it to essentially define the helper function bar. Turns out I can:
foo :: Int -> String
foo n = bar $ show n
where bar [] = ""
bar (c:s) = "-" ++ bar s
Unless there's a better way, I think this is the solution I'm after. It took a bit of beating back my imperative tendencies to see this, but it's starting to look logical and much more "core" than I was imagining.
Please provide an alternative answer if these assumptions are leading me off course!
It depends on whether the pattern-matching function is recursive or not.
In your example, it is called bar and is recursive.
foo :: Int -> String
foo n = bar $ show n
bar :: String -> String
bar [] = ""
bar (c:s) = "-" ++ bar s
Here, the (arguably) best solution is the one you found: use where (or let) and define it locally to foo:
foo :: Int -> String
foo n = bar $ show n
where
bar :: String -> String -- optional type annotation
bar [] = ""
bar (c:s) = "-" ++ bar s
The type annotation for the inner function is optional. Many Haskellers think that the top-level function foo should have its signature (and GHC with -Wall warns if you do not provide it) but also believe that the inner function do not have to be annotated. For what it is worth, I like to add it when I think it's non obvious from the context. Feel free to include or omit it.
When bar is not recursive, we have other options. Consider this code:
foo :: Int -> String
foo n = bar $ show n
bar :: String -> String
bar [] = "empty"
bar (c:s) = "nonempty " ++ c : s
Here, we can use case of:
foo :: Int -> String
foo n = case show n of
[] -> "empty"
(c:s) -> "nonempty " ++ c : s
This calls function show first, and then pattern-matches its result. I think this is easier to read than adding a where to define bar.
Theoretically, speaking, we could follow the case approach even in the recursive case, and leverage fix (a function from the library) to close the recursion. I do not recommend you to do this, since defining bar using where (or let) is more readable. I'm adding this less readable option here only for the sake of completeness.
foo :: Int -> String
foo n = fix (\bar x -> case x of
[] -> ""
(c:s) -> "-" ++ bar s
) $ show n
This is equivalent to the first recursive code snippet, but it requires much more time to read. The helper fix has its uses, but if I read this in actual production code I'd think the programmer is trying to show they are "clever" instead of writing simple, readable code.

Two-level type hierarchy with Haskell

I want to model 4 kinds of directions in my application: right, left, up and down. However, I want to be able to have a function that takes only the horizontal ones for a variable and the vertical ones for other variable.
To solve this, I can have two types: HorizontalDirection and VerticalDirection:
data HorizontalDirection = RightDir | LeftDir
data VerticalDirection = UpDir | DownDir
foo :: HorizontalDirection -> VerticalDirection -> String
foo hDir vDir = "This works"
However, I also would like to be able to have a function that can take one type as well as the other, something like this:
bar :: Direction -> String
bar (HorizontalDirection _) = "Horizontal!"
bar (VerticalDirection _) = "Vertical!"
but this wouldn't work since HorizontalDirection and VerticalDirection aren't data constructors.
I know I can use Either and make it work, like this:
bar :: (Either HorizontalDirection VerticalDirection) -> String
bar (Left _) = "Horizontal!"
bar (Right _) = "Vertical!"
however, I wonder if I can do this without the Either type.
I also tried using typeclasses:
data HorizontalDirection = RightDir | LeftDir
data VerticalDirection = UpDir | DownDir
class Direction a
instance Direction HorizontalDirection
instance Direction VerticalDirection
baz :: Direction d => d -> String
baz RightDir = "Horizontal"
but that gives me the following compiler error:
Direction.hs:21:5: error:
• Couldn't match expected type ‘d’
with actual type ‘HorizontalDirection’
‘d’ is a rigid type variable bound by
the type signature for:
baz :: forall d. Direction d => d -> String
at Direction.hs:20:1-33
• In the pattern: RightDir
In an equation for ‘baz’: baz RightDir = "Horizontal"
• Relevant bindings include
baz :: d -> String (bound at Direction.hs:21:1)
Is my way of thinking totally wrong here? Or am I just missing something?
Instead of using Either you can declare a new data type with more meaningful names.
data Direction
= Horizontal HorizontalDirection
| Vertical VerticalDirection
bar :: Direction -> String
bar (Horizontal _) = "Horizontal!"
bar (Vertical _) = "Vertical!"
You are quite close, but you need to define the function in the class:
class Direction a where
baz :: a -> String
instance Direction HorizontalDirection where
baz _ = "Horizontal"
instance Direction VerticalDirection where
baz _ = "Vertical"
Note however that Haskell is statically typed, and the types are known at compile time.

Why doesn't this type-check in Haskell?

This doesn't type check:
module DoesntTypeCheck where {
import Prelude(Either(..));
defaultEither :: a -> Either b c -> Either a c;
defaultEither a (Left _) = Left a;
defaultEither _ b = b;
}
But this does:
module DoesTypeCheck where {
import Prelude(Either(..));
defaultEither :: a -> Either b c -> Either a c;
defaultEither a (Left _) = Left a;
defaultEither _ (Right b) = Right b;
}
The compiler is probably buggy, an Either a c type can be only Left (x::a) or Right (y::c), if it isn't Left then it is Right, and we know that Right :: b -> Either a b so Right (y::c) :: Either a c.
The problem is that when you say
defaultEither _ b = b
you're saying that the output value b is the same as the second input value. And that's only possible if the values have the same type. But you've told the compiler that the input has type Either b c, while the output has type Either a c. These are different types, so no wonder the compiler complains.
I understand what you are trying to do - but even though a value Right x (with x of type c) on its own can be of type Either d c for any d, your type signature constrains the input and output values to versions with different ds. And that means you can't use the same variable to refer to both values.
Let's try an even simpler example:
data Foo x = Bar
foobar :: Foo a -> Foo b
foobar f = f
Take a look at the definition of Foo. There's a type variable on the left-hand side (x), which never actually appears anywhere on the right-hand side. This is an example of a so-called "phantom type variable". There's a type in the type signature which doesn't actually correspond to the type of anything in the actual value. (And this is perfectly legal, by the way.)
Now if you have the expression Just True, then since True :: Bool, then Just True :: Maybe True. However, the expression Nothing is definitely a Maybe something. But with no actual value present, there's nothing to force it to be any specific maybe-type. The type variable is phantom in this case.
We have a similar thing here; Bar :: Foo x, for any x. So you would think that our definition of foobar is legal.
And you would be wrong.
You cannot pass a value of Foo a where a value of type Foo b is expected, even if they have exactly the same run-time structure. Because the type checker doesn't care about the run-time structure; it only cares about types. As far as the type checker is concerned, Foo Int is different to Foo Bool, even though at run-time there's no observable difference.
And that is why your code is rejected.
In fact, you have to write
foobar :: Foo a -> Foo b
foobar Bar = Bar
to let the type checker know that the Bar you're outputting is a new, different Bar than the one you received as input (and hence it can have a different type).
Believe it or not, this is actually a feature, not a bug. You can write code that makes it so that (for example) Foo Int behaves differently than Foo Char. Even though at run-time they're both just Bar.
The solution, as you have discovered, is to just take your value b out of Right and then immediately put it back in again. It seems pointless and silly, but it's to explicitly signal to the type checker that the types have potentially changed. It's perhaps annoying, but it's just one of those corners of the language. It's not a bug, it's purposely designed to work this way.
an Either a c type can only be...
Indeed, but in your first example, the value b does not have type Either a c! As your type signature proves, it has type Either b c. And of course, you cannot return an Either b c where an Either a c is expected. Instead, you must destructure the value and reconstruct it with the right type.
an Either a c type can be only Left (x::a) or Right (y::c), if it isn't Left then it is Right, and we know that Right :: b -> Either a b so Right (y::c) :: Either a c.
I think you are confusing type constructors with data constructors. Either is defined like this in ghc-base:
data Either a b = Left a | Right b
Either is a type constructor with two abstract variables. i.e. it takes any two types (Int, String, etc). and constructs a concrete type like Either Int String.
Left and Right on the other hand are data constructors. They take actual values like 1, "hi" and construct values like Left 1 and Right "hi".
Prelude> :t Left
Left :: a -> Either a b
Prelude> :t Right
Right :: b -> Either a b
Haskell type inference does not work with values (Left and Right). It only works on types (Either). So the type checker only knows about Either b c and Either a c - so in the first case the variables don't match.

Haskell unwrap data

If you have a data type
data Something = foo Integer
| bar Bool
Is there anyway I define "getters" that unwrap the Something type to get just the Integer or Bool? Right now it would be like (foo Integer) and (bar Bool). I just want the Integer or Boolean values.
Well, firstly you have a typo: data constructors must be uppercase:
data Something = Foo Integer
| Bar Bool
What you are asking for is exactly what pattern matching is for. If you have a Something value called s:
case s of
Foo f -> ... -- f is of type Integer in this "block"
Bar b -> ... -- b is of type Bool in this "block"
This is how you generally approach this problem, because any kind of getter on this sort of data type will throw an error if it is constructed with the "wrong" constructor, and this allows you to handle that case. You can make a safe getter with something like Maybe, but a lot of times this will end up involving more boilerplate anyway.

Haskell record syntax desugared

I understand how to use record syntax in Haskell, but I have trouble to understand what the thing inside the curly braces is.
data PairRecord = PR {foo::Int, bar::String} deriving (Eq,Show)
x = (PR {foo=1, bar="init"})
y= x {foo=23}
What is this {foo=23} thing? The last line looks as if it was an
argument to the function x, which is clearly not the case.
Is there
anything else I can do with {foo=23} except placing it right behind
a record?
Is there a formal way to desugar it like what we can do with do notation?
This syntax is called "record update" or "update using field labels" and described in Section 3.15.3 of the Haskell 2010 report. It can be desugared. The exact rules are given in the report. In your example, the desugaring of x {foo = 23} is
case x of
PR f b -> PR 23 b
_ -> error "Update error"
Note that the report uses an auxiliary function called "pick" in the desugaring that's described in the section before, 3.15.2, on "Construction using field labels".
by looking at the types:
:t PR
PR :: Int -> String -> PairRecord
so it means you need an Int and a String in order to construct a PairRecord.
Now, in the definition of the PairRecord, you've defined accessor:
:t foo
foo :: PairRecord -> Int
in order to use foo (as accessor), you needs to supply a PairRecord. You gets an
Int as return value:
foo y
23
It means as well foo alone has no meaning, this function needs a PairRecord.
As kosmikus already point out, the syntax
y= x {foo=23}
creates y from an existing PairRecord with an integer set to 23 (with the help of the accessor function).
What you need is called lenses. But firstly you must install package lens.

Resources