{"id":231,"date":"2006-12-01T13:31:36","date_gmt":"2006-12-01T13:31:36","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2006\/12\/01\/functions-types-function-types-and-type-inference\/"},"modified":"2006-12-01T13:31:36","modified_gmt":"2006-12-01T13:31:36","slug":"functions-types-function-types-and-type-inference","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2006\/12\/01\/functions-types-function-types-and-type-inference\/","title":{"rendered":"Functions, Types, Function Types, and Type Inference"},"content":{"rendered":"<p>Haskell is a strongly typed language. In fact, the type system in Haskell is both stricter and more<br \/>\nexpressive than any type system I&#8217;ve seen for any non-functional language. The moment we get beyond<br \/>\nwriting trivial integer-based functions, the type system inevitably becomes visible, so we need to<br \/>\ntake the time now to talk about it a little bit, in order to understand how it works.<\/p>\n<p><!--more--><br \/>\nOne of the most important things to recognize about Haskell&#8217;s type system is that it&#8217;s based on *type<br \/>\ninference*. What that means is that in general, you *don&#8217;t* need to provide type declarations. Based<br \/>\non how you use a value, the compiler can usually figure out what type it is. The net effect is that<br \/>\nin many Haskell programs, you don&#8217;t write *any* type declarations, but your program is still<br \/>\ncarefully type-checked. You *can* declare a type for any expression you want, but the only time you<br \/>\n*must* is when something about your code is ambiguous enough that type inference can&#8217;t properly<br \/>\nselect one type for an expression.<br \/>\nThe type inference system works on the principle of *most general type*; that is, when it&#8217;s inferring<br \/>\na type for an expression, it will always pick the most general, inclusive type that can match the<br \/>\nexpression. And that leads to one complication for beginners: Haskell&#8217;s type system is almost two<br \/>\ndifferent type systems &#8211; a basic type system, and a *meta*-type system. The meta-type system is based on something called *type classes*, which group related families of types together.<br \/>\nThe most general types that come up as a result of type inference are frequently based on type classes, rather than on specific concrete types.  A type-class in code looks sort of like a *predicate* over a type variable. For example, the type of<br \/>\nthe parameters to the &#8220;`+`&#8221; operator must be a numeric type. But since &#8220;`+`&#8221; can be used on integers,<br \/>\nfloats, complex, rationals, and so on, the type of the &#8220;`+`&#8221; operator&#8217;s parameters needs to be<br \/>\nsomething that includes all of those. The way that Haskell says that is the type is &#8220;`Num a =&gt; a`&#8221;.<br \/>\nThe way to read that is &#8220;Some type &#8216;a&#8217; such that &#8216;a&#8217; is a numeric type.&#8221;.<br \/>\nThe thing to remember is that essentially, a type-class is a type for types. A *type* can be thought<br \/>\nof as a predicate which is only true for members of that type; a *type-class* is essentially a<br \/>\npredicate over *types*, which is only true for types that are members of the type-class. What<br \/>\ntype-classes do is allow you to define a *general concept* for grouping together a family of<br \/>\nconceptually related types. Then you can write functions whose parameter or return types are formed<br \/>\nusing a type-class; the type class defines a *constraint* over a group of types that could be used in<br \/>\nthe function. So if we write a function whose parameters need to be numbers, but don&#8217;t need to be a<br \/>\n*specific kind* of number, we would write it to use Haskell will infer types based on the &#8220;`Num`&#8221;<br \/>\ntype-class: &#8220;`Num`&#8221; is the most general type-class of numbers; the more things we actually *do* with<br \/>\nnumbers, the more constrained the type becomes. For example, if we use the &#8220;\/&#8221; operator, instead of<br \/>\ninferring that the type of parameter must be an instance of the &#8220;Fractional&#8221; type-class.<br \/>\nWith that little diversion out of the way, we can get back to talking about how we&#8217;ll use types in<br \/>\nHaskell. Types start at the bottom with a bundle of *primitive* atomic types which are built in to<br \/>\nthe language: `Integer`, `Char`, `String`, `Boolean`, and quite a few more. Using those types, we can<br \/>\n*construct* more interesting types. For now, the most important constructed type is a *function<br \/>\ntype*. In Haskell, functions are just values like anything else, and so they need types. The basic form of a simple single-parameter function is &#8220;`a -&gt; b`&#8221;, where &#8220;`a`&#8221; is the type of the parameter, and &#8220;`b`&#8221; is the type of the value returned by the function.<br \/>\nSo now, let&#8217;s go back and look at our factorial function. What&#8217;s the type of our basic &#8220;`fact`&#8221;<br \/>\nfunction? According to Hugs, it&#8217;s &#8220;`Num a =&gt; a -&gt; a`&#8221;.<br \/>\nDefinitely not what you might expect. What&#8217;s happening is that the system is looking at the<br \/>\nexpression, and picking the most general type. In fact, the only things that are done with the<br \/>\nparameter are comparison, subtraction, and multiplication: so the system infers that<br \/>\nthe the parameter must be a *number*, but it can&#8217;t infer anything more than that. So it says that the type of the function parameter is a numeric type; that is, a member of the type-class &#8220;`Num`&#8221;; and that the return type of the function is the same as the type of the parameter. So the statement<br \/>\n&#8220;`Num a =&gt; a -&gt; a`&#8221; basically says that &#8220;`fact`&#8221; is a function that takes a parameter of *some* type represented by a *type variable* &#8220;`a`&#8221; and returns a value of the *same* type; and it also says that the type variable &#8220;`a`&#8221; must be a member of the meta-type  &#8220;`Num`&#8221;, which is a type-class which<br \/>\nincludes all of the numeric types.  So according to Haskell, as written the factorial function is a function which takes a parameter of *any* numeric type, and returns a value of the *same* numeric type as its parameter.<br \/>\nIf we look at that type, and think about what the factorial function actually does, there&#8217;s<br \/>\na problem. That type isn&#8217;t correct, because factorial is only defined for integers, and if we pass<br \/>\nit a non-integer value as a parameter, it will *never terminate*! But Haskell can&#8217;t figure that<br \/>\nout for itself &#8211; all it knows is that we do three things with the parameter to our function: we<br \/>\ncompare it to zero, we subtract from it, and we multiply by it. So Haskell&#8217;s most general type for<br \/>\nthat is a general numeric type. So since we&#8217;d like to prevent anyone from mis-calling factorial by<br \/>\npassing it a fraction (which will result in it never terminating), we should put in a type<br \/>\ndeclaration to force it to take the more specific type &#8220;`Integer -&gt; Integer`&#8221; &#8211; that is, a function<br \/>\nfrom an integer to an integer. The way that we&#8217;d do that is to add an *explicit type declaration*<br \/>\nbefore the function:<br \/>\nfact :: Integer -&gt; Integer<br \/>\nfact 0 = 1<br \/>\nfact n = n*fact(n-1)<br \/>\nThat does it; the compiler accepts the stronger constraint provided by our type declaration.<br \/>\nSo what we&#8217;ve seen so far is that a function type for a single parameter function is created from two<br \/>\nother types, joined by the &#8220;`-&gt;`&#8221; type-constructor. With type-classes mixed in, that can be<br \/>\n*prefixed* by type-class constraints, which specify the *type-classes* of any type variables in the<br \/>\nfunction type.<br \/>\nBefore moving on to multiple parameter functions, it&#8217;s useful to introduce a little bit of syntax.<br \/>\nSuppose we have a function like the following:<br \/>\npoly x y = x*x + 2*x*y + y*y<br \/>\nThat definition is actually a shorthand. Haskell is a lambda calculus based language,<br \/>\nso semantically, functions are really just lambda expressions: that definition is really just a binding from a name to a lambda expression.<br \/>\nIn lambda calculus, we&#8217;d write a definition like that as:<br \/>\n&gt;poly &equiv; &lambda; x y . x*x + 2*x*y + y*y<br \/>\nHaskell&#8217;s syntax is very close to that. The definition in Haskell syntax<br \/>\nusing a lambda expression would be:<br \/>\npoly = ( x y -&gt; x*x + 2*x*y + y*y)<br \/>\nThe &lambda; in the lambda expression is replaced by a backslash, which is the<br \/>\ncharacter on most keyboards that most resembles lambda; the &#8220;.&#8221; becomes an arrow.<br \/>\nNow, with that out of the way, let&#8217;s get back to multi-parameter functions. Suppose we take the poly function, and see what Hugs says about the type:<br \/>\npoly x y = x*x + 2*x*y + y*y<br \/>\n&gt;\tMain&gt; :type poly<br \/>\n&gt;\tpoly :: Num a =&gt; a -&gt; a -&gt; a<br \/>\nThis answer is very surprising to most people: it&#8217;s a *two* parameter function. So intuitively, there<br \/>\nshould by *some* grouping operator for the two parameters, to make the type say &#8220;a function that<br \/>\ntakes two a&#8217;s, and returns an a&#8221;; something like &#8220;`(a,a) -&gt; a`&#8221;.<br \/>\nBut functions in Haskell are automatically *curried*.  Currying is a term from mathematical logic; it&#8217;s based on the idea that if a function is a value, then you don&#8217;t *ever* need to be able to take more than one parameter. Instead of a two parameter function, you can write a one-parameter function that returns another one-parameter function. Since that sounds really confusing, let&#8217;s take a moment and look again at our &#8220;poly&#8221; example:<br \/>\npoly x y = x*x + 2*x*y + y*y<br \/>\nNow, suppose we knew that &#8220;x&#8221; was going to be three. Then we could write a special one-parameter function:<br \/>\npoly3 y = 3*3 + 2*3*y + y*y<br \/>\nBut we *don&#8217;t* know &#8220;`x`&#8221;. But what we *can* do is write a function that takes a *parameter* &#8220;`x`&#8221;, and returns a function where all of the references to `x` are filled in, and given a y value, will return the value of the polynomial for x and y:<br \/>\npolyn x = (y -&gt; x*x + 2*x*y + y*y)<br \/>\nIf we call &#8220;`polyn 3`&#8221;, the result is exactly what we wrote for &#8220;`poly3`&#8221;.<br \/>\nIf we call &#8220;`polyn a b`&#8221;, it&#8217;s semantically *exactly* the same thing as &#8220;`poly a b`&#8221;. (That doesn&#8217;t mean that the compiler actually *implements* multi-parameter functions by generating single-parameter functions; it generates multi-parameters functions the way you&#8217;d expect. But everything *behaves* as if it did.) So what&#8217;s the type of `polyn`? Well, it&#8217;s a function that takes a parameter of<br \/>\ntype `a`; and returns a *function* of type &#8220;`Num a =&gt; a -&gt; a`&#8221;. So, the type of `polyn` is<br \/>\n&#8220;`Num a =&gt; a -&gt; (a -&gt; a)`&#8221;; and since the precedence  and associativity rules are set up to make currying convenient, the parents in that aren&#8217;t necessary &#8211; that&#8217;s the same as &#8220;`Num a =&gt; a -&gt; a -&gt; a`&#8221;. Since &#8220;`poly`&#8221; and &#8220;`polyn`&#8221; are supposed to be semantically equivalent, that means that &#8220;`poly`&#8221;&#8216;s type must also be &#8220;`Num a =&gt; a -&gt; a -&gt; a`&#8221;.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Haskell is a strongly typed language. In fact, the type system in Haskell is both stricter and more expressive than any type system I&#8217;ve seen for any non-functional language. The moment we get beyond writing trivial integer-based functions, the type system inevitably becomes visible, so we need to take the time now to talk about [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[89],"tags":[],"class_list":["post-231","post","type-post","status-publish","format-standard","hentry","category-haskell"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-3J","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/231","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/comments?post=231"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/231\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=231"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=231"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=231"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}