It's purely for the nice sugar of the if
, then
, and else
keywords; in fact, GHC (with the RebindableSyntax
extension enabled) will desugar the syntax by simply calling whatever ifThenElse
function is in scope.
Well, I don't know of any baked in ideas that market themselves as representing "function-y" things. But there are several that come close
Categories
If you have a simple function concept that has identities and composition, than you have a category.
class Category c where
id :: c a a
(.) :: c b c -> c a b -> c a c
The disadvantage is that you cannot create a nice category instance with a set of objects (a
, b
, and c
). You can create a custom category class I suppose.
Arrows
If your functions have a notion of products and can inject arbitrary functions, than arrows are for you
class Arrow a where
arr :: (b -> c) -> a b c
first :: a b c -> a (b, d) (c, d)
second :: a b c -> a (d, b) (d, c)
ArrowApply
has a notion of application which looks important for what you want.
Applicatives
Applicatives have your notion of application, I've used them in an AST to represent function application.
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f b -> f c
There are many other ideas. But a common theme is to build up some data structure representing your function, and than pass it to an interpretation function.
This also how many free monads work. I'd suggest poking at these if you're feeling brave, they're a powerful tool for the stuff that you're suggesting and essentially let you build up a datastructure using do
notation and then collapse it into a side effecting computation with different functions. But the beauty is that these functions just operation on the datastructure, and aren't really aware of how you made it all. This is what'd I'd suggest for your example of an interpreter.
Best Answer
Haskell doesn't quite have full dependent types, although it can get very close with extensions like
DataKinds
andTypeFamilies
. The issue at the moment, as far as I know, is that value-level Haskell has explicit bottoms but type-level Haskell does not.This doesn't stop you from parametrizing types over other types, including the
DataKind
-lifting of values. As of GHC 7.6, and withDataKinds
enabled, you can use type-level naturals and strings, as well as type-level tuples, type-level lists, and the type-level liftings of any (non-higher-kinded, non-generalized, non-constrained) algebraic data types, which is similar to (but much more general than) C++'s ability to use integers in templates.