Haskell: “where” clause with multiple top-level bindings? - haskell

This has got to be a FAQ, but I can’t find it among a blizzard of questions about let vs where, so… I would like to factor an expression out of multiple top-level bindings, while scoping it only to those bindings. I can do this if I have a single binding, with a “where” clause:
foo = ... bar ... bar ...
where bar = ...
and also if I have multiple guarded equations for the same top-level binding:
foo = x | ... bar ...
| ... bar ...
where bar = ...
but there seems to be no way to have multiple top-level bindings in scope of the “where,” that is something like this:
foo = ... bar ...
baz = ... bar ...
where bar = ...
I have to define bar at the top level too. It’s not a big deal, but it would be nice to scope it more closely. Am I missing something? Thanks!

You're not missing something, it's just that a where applies only to a single expression. So with your first example, you have only one expression, in your second example the single expression is your guard, and in the third case you have two difference expressions. For reference, you can see the technical description of Haskell 98 syntax here, but the relevant part is
rhs -> = exp [where decls]
| gdrhs [where decls]
Which states that a right-hand side of a definition can consist of an expression with an optional where with declarations, or a guard right-hand side with an optional where with declarations.
If you need a binding with two functions you're going to have to define it in the same scope, that's just how it works.
There is a workaround, though. You can do something like
foo :: Int
bar :: String
(foo, bar) = (2 * baz, show baz)
where baz = 1
But I personally would prefer to see baz at the top level rather than (foo, bar) defined at the top level.

Related

Pattern matching on a Haskell function with type variable

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.

How to define multiple patterns in Frege?

I'm having some trouble defining a function in Frege that uses multiple patterns. Basically, I'm defining a mapping by iterating through a list of tuples. I've simplified it down to the following:
foo :: a -> [(a, b)] -> b
foo _ [] = [] --nothing found
foo bar (baz, zab):foobar
| bar == baz = zab
| otherwise = foo bar foobar
I get the following error:
E morse.fr:3: redefinition of `foo` introduced line 2
I've seen other examples like this that do use multiple patterns in a function definition, so I don't know what I'm doing wrong. Why am I getting an error here? I'm new to Frege (and new to Haskell), so there may be something simple I'm missing, but I really don't think this should be a problem.
I'm compiling with version 3.24-7.100.
This is a pure syntactical problem that affects newcomers to languages of the Haskell family. It won't take too long until you internalize the rule that function application has higher precedence than infix expression.
This has consequences:
Complex arguments of function application need parentheses.
In infix expressions, function applications on either side of the operator do not need parentheses (however, individual components of function application may still need them).
In Frege, in addition, the following rule holds:
The syntax of function application and infix expressions on the left hand side of a definition is identical to the one on the right hand side as far as lexemes allowed on both sides are concerned. (This holds in Haskell only when # and ~ are not used.)
This is so you can define an addition function like this:
data Number = Z | Succ Number
a + Z = a
a + Succ b = Succ a + b
Hence, when you apply this to your example, you see that syntactically, you're going to redefine the : operator. To achieve what you want, you need to write it thus:
foo bar ((baz, zab):foobar) = ....
-- ^ ^
This corresponds to the situation where you apply foo to a list you are constructing:
foo 42 (x:xs)
When you write
foo 42 x:xs
this means
(foo 42 x):xs

Data constructors without breaking the open/closed principle

I have a data constructor like this
class FooClass a where
foo :: a -> b
class BarClass a where
bar :: a -> b
data FooBar = Foo :: FooClass a => a -> IO ()
| Bar :: BarClass a => a -> IO ()
So that I can use pattern matching:
foobar :: FooBar -> a -> IO ()
foobar (Foo f) x = f (foo x)
foobar (Bar f) x = f (bar x)
However, this breaks the open/closed principle.
I'd like to be able to extend FooBar with additional methods based on other classes.
How would I implement this in Haskell?
As others have pointed out, this code is flawed in ways that obscure your question. It's also probably dangerous to try to think too hard about how OO principles translate to FP. They have a place, because much of OO is embedded in FP naturally, but it's much better to learn FP directly first and then observe the laws later as certain special cases.
In particular, we can talk about how greater refinement of types is a form of extension. For instance, comparing the types like
(Num a) => a -> IO ()
(Num a, Show a) => a -> IO ()
we can talk about how the second function takes in a set of types which is a natural subtype of the inputs to the first function. In particular, the set of possible types that can be input to the second function is a refinement of the inputs to the first. As users of these functions, there are fewer valid ways to use the second function. As implementers of these functions, there are more valid ways to implement the second function. In fact, we know the following
All values which are valid inputs to the second function are also valid inputs to the first
All functions which are correctly typed by the first signature are also correctly typed by the second.
This duality between giving and taking is explored in the study of Game semantics. The idea of "open for extension" plays out trivially in that we can always decide to ask for a more refined type, but it's almost completely uninteresting since that's just obvious in how refined types are used.
So what about ADTs (data declarations) directly? Are then Open/Closed? Mu—ADTs aren't objects, so the rule does not apply directly.
The trick to doing your example in Haskell is to use functions instead of classes:
-- FooBar is like a base class
-- with methods foo and bar.
-- I've interpreted your example liberally
-- for purposes of illustration.
-- In particular, FooBar has two methods -
-- foo and bar - with different signatures.
data FooBar = FooBar {
foo :: IO (),
bar :: Int -> Int
}
-- Use functions for classes, like in Javascript.
-- This doesn't mean Haskell is untyped, it just means classes are not types.
-- Classes are really functions that make objects.
fooClass :: Int -> FooBar
fooClass n = FooBar {
foo = putStrLn ("Foo " ++ show n)
bar = \n -> n+1
}
barClass :: FooBar
barClass = FooBar {
foo = putStrLn "Bar ",
bar = \n -> n * 2
}
-- Now we can define a function that uses FooBar and it doesn't matter
-- if the FooBar we pass in came from fooClass, barClass or something else,
-- bazClass, say.
foobar (FooBar foo bar) = do
-- invoke foo
foo
-- use bar
print (bar 7)
Here FooBar is 'open for extension' because we can create as many FooBar values as we like with different behaviours.
To 'extend' FooBar with another field, baz, without changing FooBar, fooClass or barClass, we need to declare a FooBarBaz type that includes a FooBar. We can still use our foobar function, we just have to first extract the FooBar from the FooBarBaz first.
So far, I've been keeping close to OOP. This is because Bertrand Meyer worded the open closed principle to require OOP or something very like it:
software entities (classes, modules, functions, etc.) should be open
for extension, but closed for modification
In particular, the word "extension" is traditionally interpreted as meaning "subclassing". If you're prepared to interpret the principle as merely "having extension points", then any function that takes another function as parameter is "open for extension". This is so common in functional programming that it's not considered a principle. The "parameterisation principle" just doesn't sound the same.

Difference between where bindings, let bindings and the single assignment operator (<-)

I do not understand the difference between the three syntaxes:
where a = f (b)
do a <- f (b)
do let a = f (b)
I do understand somehow though that a <- f(b) is different from the other two, in most cases where I tried all three worked. Also I read somewhere on the net that per block you should try to get along with one let binding only in order to be "idiomatic". But I never seem to manage.
How do I decide what to use?
let foo = bar in ... simply defines foo to be the exact same thing as bar within the context of ...; you could simply use textual substitution to replace all uses of foo in ... with (bar) and get the exact same result.
where clauses are similar to let...in expressions, but go at the end of a function clause, instead of being an expression. For instance,
foo x
| p1 = ... y ...
| p2 = ... y ...
where
y = ...
There is no way to rewrite this with let...in without changing the guards into if...then...elses. Often, where clauses are used over let...in clauses purely for reasons of style.
The bind operator is something different entirely. It's used in do notation to "extract" a value from a monadic computation. That is, if foo has the type m a, then after x <- foo, x has the type a. All the other "binding" forms just define names, but <- is used for binding a computation's result to a name from within a monad. <- can only be used inside a do block, so it's exclusively used to build up a larger computation in the same monad as the action you're binding the result of.
let foo = bar in do notation is just a convenience; you can rewrite:
do let foo = bar
...
as
let foo = bar
in do ...
but that gets messy when you have a lot of such bindings, as the do blocks get nested deeper and deeper.
I don't know what the advice you mentioned is talking about; you can define multiple variables in a let...in block just fine, and
let foo = ...
bar ...
in ...
is more idiomatic than
let foo = ...
in let bar = ...
in ...

Operate on values within structurally similar types in Haskell

Excuse me for my extremely limited Haskell-fu.
I have a series of data types, defined in different modules, that are structured the same way:
-- in module Foo
data Foo = Foo [Param]
-- in module Bar
data Bar = Bar [Param]
-- * many more elsewhere
I'd like to have a set of functions that operate on the list of params, eg to add and remove elements from the list (returning a new Foo or Bar with a different list of params, as appropriate).
As far as I can tell, even if I create a typeclass and create instances for each type, I'd need to define all of these functions each time, ie:
-- in some imported module
class Parameterized a where
addParam :: a -> Param -> a
-- ... other functions
-- in module Foo
instance Parameterization Foo where
addParam (Foo params) param = Foo (param:params)
-- ... other functions
-- in module Bar
instance Parameterization Bar where
-- this looks familiar...
addParam (Bar params) param = Bar (param:params)
-- ... other functions
This feels tedious -- far past the degree where I start thinking I'm doing something wrong. If you can't pattern match regardless of constructor (?) to extract a value, how can boilerplate like this be reduced?
To rebut a possible line of argument: yes, I know I could simply have one set of functions (addParam, etc), that would explicitly list each constructor and pattern match put the params -- but as I'm building this fairly modularly (the Foo and Bar modules are pretty self-contained), and I'm prototyping a system where there will be dozens of these types, a verbose centralized listing of type constructors seems... wrong.
It's quite possible (probable?) that my approach is simply flawed and that this isn't anywhere near the right way to structure the type hierarchy anyhow -- but as I can't have a single data type somewhere and add a new constructor for the type in each of these modules (?) I'm stumped at how to get a nice "plugin" feel without having to redefine simple utility functions each time. Any and all kind suggestions gladly accepted.
You can have default implementations of functions in a typeclass, e.g.
class Parameterized a where
params :: a -> [Param]
fromParams :: [Param] -> a
addParam :: a -> Param -> a
addParam x par = fromParams $ par : params x
-- ... other functions
instance Parameterized Foo where
params (Foo pars) = pars
fromParams = Foo
However, your design does look suspicious.
You could use a newtype for Foo and Bar, and then deriving the implementation based on the underlying structure (in this case, lists) automatically with -XGenerializedNewtypeDeriving.
If they're really supposed to be structurally similar, yet you've coded it in a way that no code can be shared, then that is a suspicious pattern.
It's hard to tell from your example what would be the right way.
Why do you need both Foo and Bar if they are structurally similar? Can't you just go with Foo?
If, for some reason I can't see, you need both Foo and Bar you'll have to use a type class but you can clean up the code using Template Haskell.
Something like
$(superDuper "Foo")
could generate the code
data Foo = Foo [Param]
instance Parameterization Foo where
addParam (Foo params) param = Foo (param:params)
where
superDuper :: String -> Q [Dec]
superDuper n =
let name = mkName n
dataD = DataD [] name [] [NormalC name [] ] -- correct constructor here
instD = InstanceD [] ... -- add code here
return [dataD, instD]
That would at least get rid of the boiler plate coding.

Resources