How do you define a function type in Haskell? - haskell

I'm trying to store a function type in a definition so I can reuse it, but Haskell doesn't let me do it. A function type is not a data type , nor a class, as far as I understand them. So what am I doing wrong please?
functionType = Int -> Int -> Int -> Int -> Int -> Int -> Int
myfunction :: functionType -- <-- how do I declare this thing in a definition?
myfunction a b c d e f = a*b*c*d*e*f

Type aliases use the type keyword in their declaration; also, as usual for the declaration of new type forms, the newly declared alias must start with an upper case letter*. So:
type FunctionType = Int -> Int -- -> ...
functionValue :: FunctionType
functionValue a = a
* ...or punctuation. Why doesn't the usual "upper-case" punctuation restriction apply? No idea. I never thought about it before trying to write this answer, and now that I have, I find that a bit weird. Perhaps the upper-case restriction on the declaration of new types should be removed!

Related

Strict type alias in Haskell

Suppose I have a recursive function taking 3 integers, each having a different meaning, e.g.
func :: Int -> Int -> Int -> SomeType1 -> SomeType2
What I want is to prevent myself from mistyping the order of the arguments like this (somewhere in the func implementation):
func a b c t = f b a c ( someProcessing t )
The easiest way I've come up with is to define type aliases like
type FuncFirstArg = Int
type FuncSecondArg = Int
type FuncThirdArg = Int
And change func signature:
func :: FuncFirstArg -> FuncSecondArg -> FuncThirdArg -> SomeType1 -> SomeType2
But it seems like this approach doesn't work as I intended. Why does Haskell still allow me to pass FuncSecondArg as a first argument and so on. Is there a way to do what I want without declaring datatypes?
type in Haskell is a rename of an existing type. Just like String and [Char] are fully exchangeable, so are FuncFirstArg and Int, and by transition FuncSecondArg as well.
The most normal solution is to use a newtype which was introduced exactly for the purpose of what you try to achieve. For convenience, it is good to declare it as a record:
newtype FuncFirstArg = FuncFirstArg {unFuncFirstArg :: Int}
Note that newtype is entirely reduced during compilation time, so it has no overhead on the runtime.
However, if you have many arguments like in your example, a common strategy is to create a dedicated type for all of the parameters supplied to the function:
data FuncArgs = FuncArgs
{ funcA :: Int
, funcB :: Int
, funcC :: Int
, funcT :: Sometype1
}
f :: FuncArgs -> Sometype2
Yes, it has some bad impact on currying and partial application, but in many cases you can deal with it by providing predefined argument packs or even uncurry the function:
defaultArgs :: Sometype1 -> FuncArgs
defaultArgs t = FuncArgs {a = 0, b = 0, c = 0, t = t}
fUnc :: Int -> Int -> Int -> SomeType1 -> SomeType2
fUnc a b c t = f $ FuncArgs a b c t
Conclusion
For the typechecker to distinguish types, the types have to be actually different. You can't skip defining new types, therefore.

What is the right way to declare data that is an extension of another data

I am modelling a set of "things". For the most part all the things have the same characteristics.
data Thing = Thing { chOne :: Int, chTwo :: Int }
There is a small subset of things that can be considered to have an "extended" set of characteristics in addition to the base set shared by all members.
chThree :: String
I'd like to have functions that can operate on both kinds of things (these functions only care about properties chOne and chTwo):
foo :: Thing -> Int
I'd also like to have functions that operate on the kind of things with the chThree characteristic.
bar :: ThingLike -> String
I could do
data ThingBase = Thing { chOne :: Int, chTwo :: Int }
data ThingExt = Thing { chOne :: Int, chTwo :: Int, chThree :: Int }
fooBase :: ThingBase -> Int
fooExt :: ThingExt -> Int
bar :: ThingExt -> String
But this is hideous.
I guess I could use type classes, but all the boilerplate suggests this is wrong:
class ThingBaseClass a of
chOne' :: Int
chTwo' :: Int
instance ThingBaseClass ThingBase where
chOne' = chOne
chTwo' = chTwo
instance ThingBaseClass ThingExt where
chOne' = chOne
chTwo' = chTwo
class ThingExtClass a of
chThree' :: String
instance ThingExtClass ThingExt where
chThree' = chThree
foo :: ThingBaseClass a => a -> Int
bar :: ThingExtClass a => a -> String
What is the right way to do this?
One way to do so, is the equivalent of OO aggregation :
data ThingExt = ThingExt { thing :: Thing, chTree :: Int }
You can then create a class as in your post
instance ThingLike ThingExt where
chOne' = chOne . thing
chTwo' = chTwo . thing
If you are using the lens library you can use makeClassy which will generate all this boiler plate for you.
You can make a data type that is a type union of the two distinct types of things:
data ThingBase = ThingBase { chBaseOne :: Int, chBaseTwo :: Int }
data ThingExt = ThingExt { chExtOne :: Int, chExtTwo :: Int, chExtThree :: Int }
data ThingLike = CreatedWithBase ThingBase |
CreatedWithExt ThingExt
Then for any function which should take either a ThingBase or a ThingExt, and do different things depending, you can do pattern matching on the type constructor:
foo :: ThingLike -> Int
foo (CreatedWithBase (ThingBase c1 c2)) = c1 + c2
foo (CreatedWithExt (ThingExt c1 c2 c3)) = c3
-- Or another way:
bar :: ThingLike -> Int
bar (CreatedWithBase v) = (chBaseOne v) + (chBaseTwo v)
bar (CreatedWithExt v) = chExtThree v
This has the benefit that it forces you to pedantically specify exactly what happens to ThingBases or ThingExts wherever they appear to be processed as part of handling a ThingLike, by creating the extra wrapping layer of constructors (the CreatedWithBase and CreatedWithExt constructors I used, whose sole purpose is to indicate which type of thing you expect at a certain point of code).
But it has the disadvantage that it doesn't allow for overloaded names for the field accessor functions. Personally I don't see this as too big of a loss, since the extra verbosity required to reference attributes acts like a natural complexity penalty and helps motivate the programmer to keep the code sparse and use fewer bad accessor/getter/setter anti-patterns. However, if you want to go far with overloaded accessor names, you should look into lenses.
This is just one idea and it's not right for every problem. The example you already give with type classes is also perfectly fine and I don't see any good reason to call it hideous.
Just about the only "bad" thing would be wanting to somehow implicitly process ThingBases differently from ThingExts without needing anything in the type signature or the pattern matching sections of a function body to explicitly tell people reading your code precisely when and where the two different types are differentiated, which would be more like a duck typing approach which is not really what you should do in Haskell.
This seems to be what you're trying to get at by trying to force both ThingBase and ThingExt to have a value constructor with the same name of just Thing -- it seems artificially nice that the same word can construct values of either type, but my feeling is it's not actually nice. I might be misunderstanding though.
A very simple solution is to introduce a type parameter:
data ThingLike a = ThingLike { chOne, chTwo :: Int, chThree :: a }
deriving Show
Then, a ThingBase is just a ThingLike with no third element, so
type ThingBase = ThingLike ()
ThingExt contains an additional Int, so
type ThingExt = ThingLike Int
This has the advantage of using only a single constructor and only three record accessors. There is minimal duplication, and writing your desired functions is simple:
foo :: ThingLike a -> Int
foo (ThingLike x y _) = x+y
bar :: ThingExt -> String
bar (ThingLike x y z) = show $ x+y+z
One option is:
data Thing = Thing { chOne :: Int, chTwo :: Int }
| OtherThing { chOne :: Int, chTwo :: Int, chThree :: String }
Another is
data Thing = Thing { chOne :: Int, chTwo :: Int, chThree :: Maybe String }
If you want to distinguish the two Things at the type level and have overloaded accessors then you need to make use of a type class.
You could use a Maybe ThingExt field on ThingBase I guess, at least if you only have one extension type.
If you have several extensions like this, you can use a combination of embedding and matching on various constructors of the embedded data type, where each constructor represents one way to extend the base structure.
Once that becomes unmanageable, classes might become unevitable, but some kind of data type composition would still be useful to avoid duplication.

Why `Just String` will be wrong in Haskell

Hi I have a trivial but exhausting question during learning myself the Parameterized Types topic in Haskell. Here is my question:
Look this is the definition of Maybe:
data Maybe a = Just a | Nothing
And we use this like:
Just "hello world"
Just 100
But why can't Just take a type variable?
For example:
Just String
Just Int
I know this problem is quite fool, but I still can't figure it out...
Well, first note that String and Int aren't type variables, but types (type constants, if you will). But that doesn't really matter for the purpose of your question.
What matters is the destinction between Haskells type language and value language. These are generally kept apart. String and Int and Maybe live in the type language, while "hello world" and 100 and Just and Nothing live in the value language. Each knows nothing about the other side. Only, the compiler knows "this discription of a value belongs to that type", but really types exist only at compile-time and values exist only at runtime.
Two things that are a bit confusing:
It's allowed to have names that exist both in the type- and value language. Best-known are () and mere synonym-type like
newtype Endo a = Endo { runEndo :: a -> a }
but really these are two seperate entities: the type constructor Endo :: *->* (see below for these * thingies) and the value constructor Endo :: (a->a) -> Endo a. They just happen to share the same name, but in completely different scopes – much like when you declare both addTwo x = x + 2 and greet x = "Hello "++x, where both uses of the x symbol have nothing to do with each other.
The data syntax seems to intermingle types and values. Everywhere else, types and values must always be separated by a ::, most typically in signatures
"hello world" :: String
100 :: Int
Just :: Int -> Maybe Int
{-hence-}Just 100 :: Maybe Int
Nothing :: Maybe Int
foo :: (Num a, Ord a) => a -> Maybe a -- this really means `forall a . (Num a, Ord a) => a -> Maybe a
foo n | n <= 0 = Nothing
| otherwise = Just $ n - 1
and indeed that syntax can be used to define data in more distinctive way too, if you enable -XGADTs:
data Maybe a where
Just :: a -> Maybe a
Nothing :: Maybe a
Now we have the :: again as a clear distinction between value-level (left) and type-level.
You can actually take it up one more level: the above declaration can also be written
data Maybe :: * -> * where
Just :: a -> Maybe a
Nothing :: Maybe a
Here Maybe :: * -> * means, "Maybe is a type-level thing that has kind * -> *", i.e. it takes a type-level argument of kind * (such as Int) and returns another type-level thing of kind * (here, Maybe Int). Kinds are to types as types are to values.
You can certainly declare data Maybe a = Just String | Nothing, and you can declare data Maybe a = Just Int | Nothing, but only one of them at a time. Using a type variable permits to declare in what way the type of the contents of the constructed values change with the value of the type variable. So data Maybe a = Just a | Nothing tells us that the contents "inside" Just is exactly of the type passed to Maybe. That way Maybe String means that "inside" Just there is a value of type String, and Maybe Int means that "inside" Just there is a value of type Int.

Apply polymorphic function in a GHC plugin

I would like to write a GHC plugin which "adds a hook" to each function. Say I want to apply a function addHook of type Ord a => (a -> b) -> a -> b to the right-hand side of each function binding, transforming
foo = [RHS]
into
foo = addHook [RHS]
This works fine if I'm only interested in adding hooks to functions of type Int -> Int, in which case I make addHook also to have type (Int -> Int) -> Int -> Int, and invoke mkCoreApp [AddHook] [RHS] and bind it to foo in my GHC plugin.
However, if I want addHook to be polymorphic as described above, the transformed GHC Core for an Int -> Int function should look like
foo = addHook # GHC.Types.Int # GHC.Types.Int GHC.Classes.$fOrdInt [RHS]
Notice that there should be some type information attached, but I cannot find a way to construct these in the plugin, and GHC panics without those. Any suggestion would be appreciated.

Understanding the type error: "expected signature Int*Int->Int but got Int*Int->Int"

The comments on Steve Yegge's post about server-side Javascript started discussing the merits of type systems in languages and this comment describes:
... examples from H-M style systems where you can get things like:
expected signature Int*Int->Int but got Int*Int->Int
Can you give an example of a function definition (or two?) and a function call that would produce that error? That looks like it might be quite hard to debug in a large-ish program.
Also, might I have seen a similar error in Miranda? (I have not used it in 15 years and so my memory of it is vague)
I'd take Yegge's (and Ola Bini's) opinions on static typing with a grain of salt. If you appreciate what static typing gives you, you'll learn how the type system of the programming language you choose works.
IIRC, ML uses the '*' syntax for tuples. <type> * <type> is a tuple type with two elements. So, (1, 2) would have int * int type.
Both Haskell and ML use -> for functions. In ML, int * int -> int would be the type of a function that takes a tuple of int and int and maps it to an int.
One of the reasons you might see an error that looks vaguely like the one Ola quoted when coming to ML from a different language, is if you try and pass arguments using parentheses and commas, like one would in C or Pascal, to a function that takes two parameters.
The trouble is, functional languages generally model functions of more than one parameter as functions returning functions; all functions only take a single argument. If the function should take two arguments, it instead takes an argument and returns a function of a single argument, which returns the final result, and so on. To make all this legible, function application is done simply by conjunction (i.e. placing the expressions beside one another).
So, a simple function in ML (note: I'm using F# as my ML) might look a bit like:
let f x y = x + y;;
It has type:
val f : int -> int -> int
(A function taking an integer and returning a function which itself takes an integer and returns an integer.)
However, if you naively call it with a tuple:
f(1, 2)
... you'll get an error, because you passed an int*int to something expecting an int.
I expect that this is the "problem" Ola was trying to cast aspersions at. I don't think the problem is as bad as he thinks, though; certainly, it's far worse in C++ templates.
It's possible that this was in reference to a badly-written compiler which failed to insert parentheses to disambiguate error messages. Specifically, the function expected a tuple of int and returned an int, but you passed a tuple of int and a function from int to int. More concretely (in ML):
fun f g = g (1, 2);
f (42, fn x => x * 2)
This will produce a type error similar to the following:
Expected type int * int -> int, got type int * (int -> int)
If the parentheses are omitted, this error can be annoyingly ambiguous.
It's worth noting that this problem is far from being specific to Hindley-Milner. In fact, I can't think of any weird type errors which are specific to H-M. At least, none like the example given. I suspect that Ola was just blowing smoke.
Since many functional language allow you to rebind type names in the same way you can rebind variables, it's actually quite easy to end up with an error like this, especially if you use somewhat generic names for your types (e.g., t) in different modules. Here's a simple example in OCaml:
# let f x = x + 1;;
val f : int -> int = <fun>
# type int = Foo of string;;
type int = Foo of string
# f (Foo "hello");;
This expression has type int but is here used with type int
What I've done here is rebind the type identifier int to a new type that is incompatible with the built-in int type. With a little bit more effort, we can get more-or-less the same error as above:
# let f g x y = g(x,y) + x + y;;
val f : (int * int -> int) -> int -> int -> int = <fun>
# type int = Foo of int;;
type int = Foo of int
# let h (Foo a, Foo b) = (Foo a);;
val h : int * int -> int = <fun>
# f h;;
This expression has type int * int -> int but is here used with type
int * int -> int

Resources