![]() ![]() In JavaScript and other weakly typed languages, you can put almost anything inside of an expression. It's a type constructor that takes a parameter and then returns a concrete type. ![]() This is because, like we've seen, a has to be a concrete type, but Maybe isn't a concrete type. That's why we can't do something like instance Eq Maybe where Looking back at the Eq typeclass definition above, we see that a is used as a concrete type because all of the types in function have to be concrete. This essentially means that type a becomes an instance of Eq prior to becoming an instance of Num. What the definition above states that for any given type a, it must be an instance of Eq. The class declaration for Num is a bit long, but here's the first part. You can also make typeclasses that are subclasses of other typeclasses. We then write type declarations for both equality functions along with function definitions. Firstly, class Eq a where means that we're defining a typeclass that's called Eq that takes a type variable of a. class Eq a whereĪbove we defined the Eq typeclass. As an example, if we have a type Car that compares two cars with the equality function =, then it makes sense for Car to be an instance of Eq. For example, the Eq typeclass is for stuff that can be equated. Typeclasses 102Ī quick recap on typeclasses: typeclasses are like inferences.Ī typeclass defines some behavior, and then types that can behave in that way are made instances of that typeclass. In the insertion function, we are presented with the edge condition as a pattern. The singleton function is just a shortcut for making a node that has something and two empty sub-trees. Singleton x = Node x EmptyTree EmptyTree treeInsert :: ( Ord a) => a -> Tree a -> Tree a Once we reach an empty tree, we just insert a node with that value inserted into an empty tree. We do the same for every subsequent node until we reach an empty tree. We can do this by comparing the value we want to insert into the root node and then if its smaller, we go left, if it's larger, we go right. What's going on here? Instead of manually builing a tree, we're going to make a function that takes a tree and an element and then inserts an element. data Tree a = EmptyTree | Node a ( Tree a) ( Tree a) deriving ( Show, Read, Eq) Right now we'll just be implementing a normal binary search tree, though. ![]() The only difference is that instead of being a normal tree, they used balanced binary search trees, which are always balanced. Sets and maps from Data.Set and Data.Map are implemented when using trees. fetchUser :: MonadDB m => Id User -> m User Implementing a binary search tree This makes it possible to write functions that operate on specific kinds of ids, and those invariants will be statically checked by the compiler, even through the runtime representation is entirely identical. No matter what a is, Id is just a piece of text. The kind of value is specified as the type parameter, a, but it isn't used anywhere. This type represents an id for some kind of value. The basic idea for a phantom type is simple it's a type parameter that isn't actually used to represent a given runtime value. They serve as the foundation for a lot of other interesting type-level manipulations that can make Haskell an extremely interesting language. Phantom types are a rather simple concept, but a powerful one at that. Notes relating to the implementation of record syntax when defining custom types can be found in 07-customTypes.hs Type parameters data Car = Car deriving ( Show, Read, Eq, Ord) Rectangle :: Float -> Float -> Float -> Float -> Shape data Shape = Circle Float Float Float | Rectangle Float Float Float Float ghci> :t CircleĬircle :: Float -> Float -> Float -> Shape The actual definition of Int omits the ellipses for a ton of numbers. Int is fairly straightforward, with the first and last values being the upper and lower bounds of the type. The value constructors define the values that our type can have, while the | is read as or. The type name, Bool, and each part of the type definition separated by the | is a value constructor. data Bool = False | Trueĭata means that we're defining a new type. We can use that data keyword to define a type. They're awesome, but now its time to venture into making our own types. Up to now we've worked with the basic types: Bool, Int, Char, Maybe, etc. ![]()
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |