Skip to content

Latest commit

 

History

History
173 lines (138 loc) · 6.31 KB

PythagorasTutorial.md

File metadata and controls

173 lines (138 loc) · 6.31 KB

How to write a small library in Haskell

The library we will be building today is called Pythagoras. It is a simple library for calculating the length of a triangle using the Pythagorean Theorem.

The repository for Pathagoras can be found on Github


Prerequisites

  • A basic understanding of haskell type classes.
  • Basic understanding of the terminal and GHCi
  • Eager to learn

Goals

  • Simple functions to calculate the length of triangles using the Pythagorean Theorem.
  • Simple names for functions to minimize confusion.
  • Learn

Steps

  1. Create Directory called Pythagoras
  2. cd Inside your Pythagoras directory and issue the command
    cabal init
  3. At this point you will be prompted to configure your .cabal package. These are the details you find on the homepage of a hackage library under Properties. It looks like this, well ours will:

-- Initial Pythagoras.cabal generated by cabal init. For further -- documentation, see http://haskell.org/cabal/users-guide/

name:                Pythagoras
version:             0.1.0.0
synopsis:            A simple library for doing the Pythagorean Theorem.
homepage:            http://github.com/Cortlandd/Pythagoras
license:             PublicDomain
license-file:        LICENSE
author:              Cortland Walker
maintainer:          cortlandits@gmail.com
category:            Math
build-type:          Simple
cabal-version:       >=1.10

library
  -- Other library packages from which modules are imported.
  build-depends:       base >=4.8 && <4.9
  -- Directories containing source files.
  hs-source-dirs:      src
  -- Base language which the package is written in.
  default-language:    Haskell2010
```

3.1. In some cases your src would look something like this for a library:

    src/
        Pythagoras.hs
        Pythagoras

With this, the Pythagoras/ folder is where your source code goes, and Pythagoras.hs is the module file which imports all the source code from Pythagoras/. But in our case, we will only need 1 file inside of our src.

  1. Now you're going to create your source code file inside src. Name it Pythagoras.hs. When you first go into GHCi, you see something called Prelude>. Well, Prelude is simply a module being loaded by default With it, comes it's functions (map, head, sum, etc). With that file created, start by setting up the module name:

    -- Pythagoras.hs
    module Pythagoras where
  2. Next, were going to write our functions. They will takes 2 arguments and are in sequential order of the abc's. We will do this for each function.

    -- Pythagoras.hs
    module Pythagoras where
    
    solveForA :: (Floating a, Ord a) => a -> a -> a
    solveForA b c
      | b > c     = error "The hypotenuse c is always larger than the legs a and b."
      | otherwise = sqrt (c^2 - b^2)
    
    solveForB :: (Floating a, Ord a) => a -> a -> a
    solveForB a c 
      | a > c     = error "The hypotenuse c is always larger than the legs a and b." 
      | otherwise = sqrt (c^2 - a^2) 
    
    solveForC :: (Floating a) => a -> a -> a
    solveForC a b = sqrt (a^2 + b^2)
  3. Lets test the functions inside Pythagoras.hs. Save this file, and inside the Pythagoras.hs directory, run GHCi:

    #> GHCi
    Prelude> :l Pythagoras.hs
    [1 of 1] Compiling Pythagoras   ( Pythagoras.hs, interrupted )
    Ok, modules loaded: Pythagoras.
    *Pythagoras> :browse
    solveForA :: (Floating a, Ord a) => a -> a -> a
    solveForB :: (Floating a, Ord a) => a -> a -> a
    solveForC :: (Floating a) => a -> a -> a
    *Pythagoras> solveForA 9 15
    12.0
    *Pythagoras> solveForB 4 8
    6.928203230275509
    *Pythagoras> solveForC 5 12
    13.0

    You now have access to all of your previously created functions from Pythagoras.hs

  4. Now, lets use the functions in our library from another source file. Inside the same directory as Pythagoras.hs, create a file called TestPythagoras.hs.

    -- TestPythagoras.hs
    module TestPythagoras where
    
    import Pythagoras
    
    main :: IO ()
    main = print (solveForA 7 25)

    Now if you load TestPythagoras.hs inside GHCi

    #> GHCi
    Prelude> :l TestPythagoras.hs
    [1 of 2] Compiling Pythagoras   ( Pythagoras.hs, interpreted )
    [2 of 2] Compiling TestPythagoras   ( TestPythagoras.hs, interpreted )
    Ok, modules loaded: Pythagoras, TestPythagoras
    *TestPythagoras> main
    24.0
  5. Now you officially have a working Haskell Library. Uploading to Hackage is probably beyond the scope of this tutorial so I won't. But for now, make additions to Pythagoras, perfect it. Go out and explore the world of Haskell.

Bonus Material

Tips from beginner to beginner||reader
  1. Know your arsenal. Be aware of the tools at your disposal in haskell (head, tail, map, foldr, etc). Ignorance of this can confuse you. You get coders block. Don't reinvent the wheel when you don't have to.
  2. A little trick I do that helps me write functions. Write out your intended functions use case.
    -- I have my type signature
    all :: (a -> Bool) -> [a] -> Bool
    
    -- This is how I want all to behave
    all even [2, 4, 6, 8, 10]
    => True
    {- "even" is already a function in Haskell. Again, back to tip 1. Know your arsenal. Don't reinvent the wheel if it isnt necessary. -}
Making Pythagoras more efficient.

The initial Pythagoras.hs was meant to be beginner friendly, and easy to understand. A way to build it which...WHY IS THIS DONE. PROFESSIONAL INPUT WOULD BE HELPFUL

-- All functions will be contained in a module called: Pythagoras
module Pythagoras where {- a² + b² = c² -}

solveForA :: (Floating a, Ord a) => a -> a -> Maybe a
solveForA b c
  | b > c     = Nothing
  | otherwise = Just (sqrt (c^2 - b^2))

solveForB :: (Floating a, Ord a) => a -> a -> Maybe a
solveForB a c 
  | a > c     = Nothing
  | otherwise = Just (sqrt (c^2 - a^2)) 

solveForC :: (Floating a) => a -> a -> Maybe a
solveForC a b = Just (sqrt (a^2 + b^2))
verboseSolveFor
-- Hmm, where to begin. How do I approach this?