Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I name a function signature?

I'm passing around a partially applied function. The full signature is:

import Data.Map as Map 
-- Update the correct bin of the histogram based on the min value, bin width,
-- the histogram stored as a map, and the actual value we are interested in.
updateHist :: Double -> Double -> Map.Map Bin Double -> Double -> 
              Map.Map Bin Double

The function updates a Map which stores data for a histogram. The first two parameters give the bottom bounds of data we are interested, the next is the bin width for the histogram. I fill these values in when the program starts up and pass the partially applied function all over the module. This means I have a ton of functions with a signature like:

-- Extra the data out of the string and update the histogram (in the Map) with it.
doSomething :: String -> (Map.Map Bin Double -> Double -> Map.Map Bin Double) -> 
               Map.Map Bin Double

This is all fine and dandy, but writing "(Map.Map Bin Double -> Double -> Map.Map Bin Double)" is rather verbose. I'd like to replace them all with "UpdateHistFunc" as a type but for some reason I keep failing.

I tried:

newtype UpdateHistFunc = Map.Map Bin Double -> Double -> Map.Map Bin Double

This failed with the error:

HistogramForColumn.hs:84:44: parse error on input `->'

What am I doing wrong?

like image 866
Tim Perry Avatar asked Jun 17 '11 21:06

Tim Perry


1 Answers

Are you confusing type and newtype here?

Using type defines a type synonym, which is what you seem to be trying to do, whereas newtype creates a new type that needs a constructor name, like with data.

In other words, you probably want this:

type UpdateHistFunc = Map.Map Bin Double -> Double -> Map.Map Bin Double

...or maybe this:

newtype UpdateHistFunc = UpdateHistFunc (Map.Map Bin Double -> Double -> Map.Map Bin Double)

The latter obviously needs to be "unwrapped" in order to apply the function.


For reference:

  • data defines a new algebraic data type, which can be recursive, have distinct instances of type classes, introduces an extra layer of possible laziness, all that stuff.
  • newtype defines a data type with a single constructor taking a single argument, which can be recursive and have distinct instances, but only for type checking; after compilation, it's equivalent to the type it contains.
  • type defines a type synonym, which can't be recursive or have distinct instances, is fully expanded when type checking, and amounts to little more than a macro.

If you're wondering about the semantic distinction between data and newtype where "extra laziness" is concerned, compare these two types and the possible values they can have:

data DType = DCon DType

newtype NType = NCon NType

For instance, what do you think these functions will do if applied to undefined vs. DCon undefined and NCon undefined, respectively?

fd (DCon x) = x
fn (NCon x) = x
like image 89
C. A. McCann Avatar answered Oct 25 '22 22:10

C. A. McCann