Understanding Haskell types

I recently took a break from Perl work to study at the Recurse Center. I’m learning Haskell, and it’s been an interesting adventure so far. I’d heard good things about Haskell’s type system and started with an introductory book Learn You a Haskell for Great Good!. The book is filled with cartoonish humor - “how hard can this be?” I asked myself. The answer was “hard”. I found Haskell’s type system to be counter-intuitive, so this article lays out my understanding of Haskell types. If you’re a programmer with an imperative programming background, you might find this useful.

Your intuition is wrong

For imperative-language programmers, Haskell keywords are likely to mislead. Take the type keyword for instance. It’s not for creating new types per se, but type synonyms, which are like aliases for existing types. I might use it like this:

type FirstName = String
type LastName = String
type Age = Int

One way to declare new types is with the data keyword (naturally!). If I wanted to create a person type, I could use data :

data Person = Person String String Int

This declares a new type called Person with 2 strings and 1 integer as attributes. But I could also use our type synonyms from the earlier example, and clarify my intentions:

data Person = Person FirstName LastName Age

Functions and types

In Haskell function signatures can be restricted by types. I can create a function to tell which of two people is older:

eldest :: Person -> Person -> String
eldest (Person x1 y1 z1) (Person x2 y2 z2)
  | z1 > z2   = x1 ++ " " ++ y1 ++ " is older"
  | z1 < z2   = x2 ++ " " ++ y2 ++ " is older"
  | otherwise = "They're the same age!"

This is a lot of new syntax, so bear with me. The first line declares a function called eldest which takes two persons and returns a string. The second line assigns the attributes of each person to variables. The rest of the function tests which person is older and returns an appropriate message. I’ll save all of this code into a file called “person.hs”, so I can test the function in the Haskell REPL, ghci

ghci> :l person.hs
[1 of 1] Compiling Main             ( person.hs, interpreted )
Ok, modules loaded: Main.
ghci> let a = Person "Bart" "Simpson" 10
ghci> let b = Person "Lisa" "Simpson" 7
ghci> eldest a b
"Bart Simpson is older"

Sometimes we don’t need to access all of the attributes of a type in a function. In these cases Haskell let’s you use _ as a placeholder, that won’t be assigned to a variable. For example to print the initials of a person, I only need to know their first and last names:

initials :: Person -> String
initials (Person x y _) = [head x,'.',head y, '.']

The second line of code assigns a person’s firstname to x and lastname to y. It then takes the first char of each using head and returns a new list of chars with a dot after each char. I can test the function by reloading “person.hs”:

ghci> :l person.hs
[1 of 1] Compiling Main             ( person.hs, interpreted )
Ok, modules loaded: Main.
ghci> let a = Person "Maggie" "Simpson" 1
ghci> initials a
"M.S."

Typeclasses

Typeclasses are similar to traits (roles in Perl-speak) for types. For example, integers are instances of typeclasses like Ord as they are orderable, Num as they are numbers, and so on. Each typeclass defines functions for handling types in specific contexts. The Eq typeclass adds the ability to compare types for equality using operators like ==.

By generalizing the properties of types with typeclasses, Haskell can support generic functions which operate on typeclasses, instead of being restricted to one type. The signature of the quicksort function from Learn You a Haskell is a great example of this:

quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) 
    let smallerSorted = quicksort [a | a <- xs, a <= x]
        biggerSorted = quicksort [a | a <- xs, a > x]
    in  smallerSorted ++ [x] ++ biggerSorted

This declares a new function called quicksort which is restricted to lists of orderable types. Ignore the body and just focus on the first line of code, the function signature. The code (Ord a) defines the typeclass constraint for the function. This function can be used to sort anything orderable, like lists of numbers. Aren’t strings just lists of chars? I guess we can sort them with quicksort too then.

Instance and Class

If you saw the instance keyword in some Haskell code, you might think “aha, a singleton constructor!” but actually instance is used to make types instances of typeclasses. This makes sense when you consider that every type is an instance of a typeclass. Revisiting my Person type from earlier, what if I wanted to make it orderable? Typically in the English-speaking parts of the world, people are sorted by their last name, so I’m going to implement it that way:

data Person = Person FirstName LastName Age deriving (Eq, Show)

instance Ord Person where
  compare (Person _ a _) (Person _ b _) = compare a b

I start by updating the type declaration of Person with deriving (Eq, Show). These operate on the whole type (all of its attributes together). Eq will let Haskell compare Persons for equality and Show just let’s Haskell serialize the type as a string. The second line of code uses instance to make persons orderable. The final line implements a comparison function using the lastname attribute of the Person. I can test the code using the quicksortfunction declared above.

ghci> :l person.hs
[1 of 1] Compiling Main             ( person.hs, interpreted )
Ok, modules loaded: Main.
ghci> let a = Person "Jason" "Bourne" 37
ghci> let b = Person "James" "Bond" 42
ghci> quicksort [a,b]
[Person "James" "Bond" 43,Person "Jason" "Bourne" 37]

This sorted our list of people by their lastname, and because Person is an instance of Show, Haskell was able to print out the detail to the command line. Not bad!

The final keyword to be aware of is class. By now it shouldn’t surprise you to find out that class is not for declaring classes like in imperative programming, but for creating new typeclasses. You probably won’t use this much when starting out with Haskell, but it’s useful to keep in mind for reducing repetitive code. If you have multiple sets of code doing very similar things for different types, consider creating a new typeclass and merging the functions to operate on the new type class, to keep things DRY.

Code complete

This is the finished code:

--person.hs
type FirstName = String
type LastName  = String
type Age = Int 

data Person = Person FirstName LastName Age deriving (Eq, Show)

eldest :: Person -> Person -> String
eldest (Person x1 y1 z1) (Person x2 y2 z2)
  | z1 > z2   = x1 ++ " " ++ y1 ++ " is older"
  | z1 < z2   = x2 ++ " " ++ y2 ++ " is older"
  | otherwise = "They're the same age!"

initials :: Person -> String
initials (Person x y _) = [head x,'.',head y, '.']

quicksort [] = []
quicksort (x:xs) 
    let smallerSorted = quicksort [a | a <- xs, a <= x]
        biggerSorted = quicksort [a | a <- xs, a > x]
    in  smallerSorted ++ [x] ++ biggerSorted

instance Ord Person where
  compare (Person _ a _) (Person _ b _) = compare a b

Learn Haskell the Hard Way

Despite its childish demeanor, Learn You a Haskell goes deep into the Haskell type system and can be a bit long-winded at times. My current learning method involves reading the book, and typing out every code example, and studying Penn State’s cis194 course. Both are free. O’Reilly’s Real World Haskell is also available for free online, and emphasizes more immediate practical uses of Haskell. It’s good for when you’re tired of coding binary search trees and sorting algorithms. If you find yourself needing to lookup a Haskell term, DuckDuckGo has the!h bang, which searches Hoogle automatically.

CCF大数据与计算智能大赛-面向电信行业存量用户的智能套餐个性化匹配模型联通赛-复赛第二名-【多分类,embedding】.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值