diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,58 +3,63 @@
 See git repo for more detailed commit information.
 
 ## 0.1.0.0
-First functional prototype.
+- First functional prototype.
 
 ## 0.1.0.1
-Dependency versions reworked.
+- Dependency versions reworked.
 
 ## 0.2.0.0
-Help messages improved. Module structure refactored. Documentation begun.
+- Help messages improved. Module structure refactored. Documentation begun.
 
 ## 0.2.0.1
-Revised cabal version in attempt to fix build error on Hackage. Build works
-locally, suspect the problem is a quirk of Hackage build system.
-Added some more documentation.
+- Revised cabal version in attempt to fix build error on Hackage. Build works
+- locally, suspect the problem is a quirk of Hackage build system.
+- Added some more documentation.
 
 ## 0.2.0.2
-Internal library now unnamed. Hoping this fixes Hackage build fail.
+- Internal library now unnamed. Hoping this fixes Hackage build fail.
 
 ## 0.2.0.3
-Added docs for yaku functions.
-Reworked seven pairs detection to ensure hand has 14 tiles.
-9 gates now checks that the hand is closed.
+- Added docs for yaku functions.
+- Reworked seven pairs detection to ensure hand has 14 tiles.
+- 9 gates now checks that the hand is closed.
 
 ## 0.3.0.0
-Fixed error in scoring triple triplets, was previously scored as 1 han open.
-Implemented new backend for scoring and yaku detection via "context" based
+- Fixed error in scoring triple triplets, was previously scored as 1 han open.
+- Implemented new backend for scoring and yaku detection via "context" based
 approach, defined in new Context submodule. This helps simplify function
 signatures for operations that need many pieces of information besides just the
 superficial composition of a hand.
 
 ## 0.3.1.0
-Now only ask for dora after we know the hand is not a yakuman, as part of the
+- Now only ask for dora after we know the hand is not a yakuman, as part of the
 mkContext function (previously handled dora in displayHandScore).
-Four concealed triplets now asks about concealment. It wasn't doing this before,
+- Four concealed triplets now asks about concealment. It wasn't doing this before,
 a bug introduced by the refactor, since mkYakumanContext intentionally gets less
 information than mkYakuContext since generally it needs less.
-Now only ask for wind context if we see a wind tile in the hand. Note even a
+- Now only ask for wind context if we see a wind tile in the hand. Note even a
 wind pair could matter - it won't affect most yaku but affects Fu.
 Speaking of - 
     NOTE: Seat+Round wind pair counts as a yakuhai pair and awards
     2+2=4 Fu. Some rulesets would only award 2 Fu.
 
 ## 0.4.0.0
-Extended documentation. Old getFu replaced with new one (previously _getFu).
-Removed old getYaku function
+- Extended documentation. Old getFu replaced with new one (previously _getFu).
+- Removed old getYaku function
 
 ## 0.4.0.1
-Fixed catastrophic failure affecting waits command.
+- Fixed catastrophic failure affecting waits command.
 
 ## 0.4.1.0
-Fixed further problems with waits command. Previously, partial hands with kans
+- Fixed further problems with waits command. Previously, partial hands with kans
 were not considered. To fix this and also streamline the internal API, formMelds
 now returns all ways of pulling melds out of a hand, INCLUDING KANS. Previously
-the caller had to handle kans themselves. This makes the interpretHand function
+the caller had to handle kans themself. This makes the interpretHand function
 simpler, and fixes getWaits.
 
-
+## 0.5.0.0
+- Sub 5-han mangans are now named correctly
+- Reworked meld forming functions. Can now get all ways of pulling out melds, or
+  just all ways of pulling out a complete set of melds (when the hand is
+  complete to begin with)
+- Internal code refactors according to hlint
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@
         Numeric tiles of the same suit, and honour tiles, can be 
         grouped as seen in the examples (but needn't be).
 
-        In scoring a hand, dora and seat/round wind must be supplied,
-        also in this format.
+        In scoring a hand, dora and seat/round wind may be required,
+        also supplied in this format.
 
 Internal libraries are also exposed.
 
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -6,6 +6,8 @@
 -}
 module Main (main) where
 
+import Data.Version (showVersion)
+import Paths_riichi_scoring (version)
 import Riichi.Display
 import Riichi.Meld
 import System.Environment (getArgs)
@@ -17,10 +19,11 @@
     let list = ['1' .. '9'] ++ "NESWrgw"
     case args of
         [] -> putStrLn "No arguments supplied. Run riichi --help for more info."
-        (arg : [])
-            | (arg `elem` ["--help", "-h", "help"]) -> putStrLn helpString
-            | (arg `elem` ["yaku", "waits", "score"]) -> putStrLn "Missing hand"
-            | (head arg) `elem` list -> displayHandYaku $ mkHand arg
+        [arg]
+            | arg `elem` ["--help", "-h", "help"] -> putStrLn helpString
+            | arg `elem` ["--version", "-v", "version"] -> putStrLn $ "riichi-scoring: " ++ showVersion version
+            | arg `elem` ["yaku", "waits", "score"] -> putStrLn "Missing hand"
+            | head arg `elem` list -> displayHandYaku $ mkHand arg
             | otherwise -> putStrLn "Command not recognised"
         (arg1 : arg2 : _)
             | arg1 == "yaku" -> displayHandYaku $ mkHand arg2
@@ -30,18 +33,20 @@
 
 helpString :: String
 helpString =
-    "Command riichi:\n\tPossible subcommands: yaku, waits, score (default = yaku)\n\nUsage:\
-    \\n\triichi <subcommand> \"<hand>\"\
-    \\n\n\t\"yaku\" and \"score\" subcommands expect a full hand.\
-    \\n\t\"waits\" subcommand expects a hand that is tenpai.\
-    \\n\n\tExample hands include:\
-    \\n\t\t\"123p 234m 444p rrrr NN\"\
-    \\n\t\t\"344556s 444p 222m EE\"\
-    \\n\t\t\"19p 19s 19m 1p NESWrgw\"\
-    \\n\n\tIn detail, numeric tiles are denoted (1-9) + (m, p, or s),\
-    \\n\tWinds are denoted N, E, S, W, and Dragons are r, w, g.\
-    \\n\tA 0 can be used to denote a red five.\
-    \\n\tNumeric tiles of the same suit, and honour tiles, can be \
-    \\n\tgrouped as seen in the examples (but needn't be).\
-    \\n\n\tIn scoring a hand, dora and seat/round wind must be supplied,\
-    \\n\talso in this format."
+    "Command riichi: version = "
+        ++ showVersion version
+        ++ " \n\tPossible subcommands: yaku, waits, score (default = yaku)\n\nUsage:\
+           \\n\triichi <subcommand> \"<hand>\"\
+           \\n\n\t\"yaku\" and \"score\" subcommands expect a full hand.\
+           \\n\t\"waits\" subcommand expects a hand that is tenpai.\
+           \\n\n\tExample hands include:\
+           \\n\t\t\"123p 234m 444p rrrr NN\"\
+           \\n\t\t\"344556s 444p 222m EE\"\
+           \\n\t\t\"19p 19s 19m 1p NESWrgw\"\
+           \\n\n\tIn detail, numeric tiles are denoted (1-9) + (m, p, or s),\
+           \\n\tWinds are denoted N, E, S, W, and Dragons are r, w, g.\
+           \\n\tA 0 can be used to denote a red five.\
+           \\n\tNumeric tiles of the same suit, and honour tiles, can be \
+           \\n\tgrouped as seen in the examples (but needn't be).\
+           \\n\n\tIn scoring a hand, dora and seat/round wind may be required,\
+           \\n\talso supplied in this format."
diff --git a/riichi-scoring.cabal b/riichi-scoring.cabal
--- a/riichi-scoring.cabal
+++ b/riichi-scoring.cabal
@@ -20,7 +20,7 @@
 -- PVP summary:     +-+------- breaking API changes
 --                  | | +----- non-breaking API additions
 --                  | | | +--- code changes with no API change
-version: 0.4.1.0
+version: 0.5.0.0
 -- A short (one-line) description of the package.
 synopsis: A CLI tool for interpreting and scoring Riichi Mahjong hands.
 -- A longer description of the package.
@@ -58,6 +58,7 @@
 
 library
   exposed-modules:
+    Paths_riichi_scoring
     Riichi.Context
     Riichi.Display
     Riichi.Meld
@@ -68,6 +69,9 @@
 
   other-modules:
     ColourStrings
+
+  autogen-modules:
+    Paths_riichi_scoring
 
   hs-source-dirs: src
   build-depends:
diff --git a/src/Riichi/Context.hs b/src/Riichi/Context.hs
--- a/src/Riichi/Context.hs
+++ b/src/Riichi/Context.hs
@@ -7,6 +7,7 @@
 module Riichi.Context where
 
 import Control.Exception (handle)
+import Control.Monad (when)
 import Data.Function ((&))
 import Riichi.Meld
 import Riichi.Tile
@@ -28,7 +29,7 @@
     , wind :: WindContext
     , isSevenPairs :: Bool
     , isThirteenOrphans :: Bool
-    , dora :: Integer
+    , dora :: Dora
     }
 
 {- | Get a basic hand context with the minimal amount of information. Defaults to a closed hand
@@ -114,7 +115,7 @@
     }
 
 -- | Ask about the waits, and return a wait context.
-askWaitContext :: IO (WaitContext)
+askWaitContext :: IO WaitContext
 askWaitContext = do
     ryanmanWait <- askYesNo "Did the hand have an open wait? [y/n]: "
     shanponWait <-
@@ -128,7 +129,7 @@
     {seatWind :: Wind, roundWind :: Wind}
 
 -- | Ask about round and seat winds, and return a wind context.
-askWindContext :: IO (WindContext)
+askWindContext :: IO WindContext
 askWindContext = do
     putStrLn "Input round and seat wind: "
     (Honour (Wind r) _) : (Honour (Wind s) _) : _ <- mkHand <$> getLine
@@ -139,7 +140,7 @@
     {isRiichi :: Bool, isIppatsu :: Bool}
 
 -- | Ask about the hand being riichi, return a riichi context.
-askRiichiContext :: IO (RiichiContext)
+askRiichiContext :: IO RiichiContext
 askRiichiContext = do
     riichi <- askYesNo "Riichi? [y/n]: "
     ippatsu <-
@@ -208,13 +209,13 @@
             , isSankantsu = sankantsu ih
             , isShousangen = shousangen ih
             , isChinitsu = fullFlush
-            , isHonitsu = halfFlush && (not fullFlush)
+            , isHonitsu = halfFlush && not fullFlush
             , -- Should these check for closed, or do we want to include them anyway?
               isRyanpeikou = twicePure && closure
-            , isIipeikou = singlePure && (not twicePure) && closure
+            , isIipeikou = singlePure && not twicePure && closure
             , isJunchan = fullyOutside
-            , isChanta = halfOutside && (not fullyOutside) && (not terminalsHonours)
-            , isHonroutou = terminalsHonours && (not fullyOutside)
+            , isChanta = halfOutside && not fullyOutside && not terminalsHonours
+            , isHonroutou = terminalsHonours && not fullyOutside
             , yakuHandContext = handContext
             , isMenzenTsumo = tsumo && closure
             , isChiitoitsu = False
@@ -241,7 +242,7 @@
             , isSankantsu = False
             , isShousangen = False
             , isChinitsu = fullFlush
-            , isHonitsu = halfFlush && (not fullFlush)
+            , isHonitsu = halfFlush && not fullFlush
             , -- Should these check for closed, or do we want to include them anyway?
               isRyanpeikou = False
             , isIipeikou = False
@@ -282,7 +283,7 @@
                 -- are all the melds. If the hand is closed, a meld could still be open so we need to ask.
                 then case maybeClosure of
                     Just False -> return False
-                    otherwise -> askYesNo "Are the four triplets all concealed? [y/n]: "
+                    _ -> askYesNo "Are the four triplets all concealed? [y/n]: "
                 else return False
         let isSuuka = suukantsu ih
         let isDaisa = daisangen ih
@@ -315,14 +316,14 @@
                             , isKokushiMusou = False
                             }
             else
-                return $ Nothing
+                return Nothing
 mkYakumanContext hand Nothing _ =
     let
         isTsuui = tsuuiisou hand
         isChinr = chinroutou hand
         isRyuui = ryuuiisou hand
      in
-        if (or [isTsuui, isChinr, isRyuui]) && chiitoitsu hand
+        if (isTsuui || isChinr || isRyuui) && chiitoitsu hand
             then
                 return $
                     Just
@@ -360,6 +361,9 @@
 -- | Overarching context type
 data Context = Context (Maybe InterpretedHand) HandContext (Either YakuContext YakumanContext)
 
+getContextDora :: Context -> Dora
+getContextDora (Context _ (HandContext{dora}) _) = dora
+
 -- | Top level interface for building a context about a hand. Determines the interpretation, yaku, yakuman etc
 mkContext :: Hand -> IO Context
 mkContext hand = do
@@ -374,7 +378,7 @@
                 return Nothing
             else do
                 let ihs = interpretHand hand
-                if length ihs == 0
+                if null ihs
                     then undefined
                     else do
                         ih <-
@@ -397,20 +401,17 @@
         Nothing -> do
             putStrLn "Input dora (or leave blank):"
             dora <- mkHand <$> getLine
-            if dora /= []
-                then
-                    putStrLn ""
-                else return ()
+            when (dora /= []) $ putStrLn ""
 
             let hand' = addDora dora hand
             -- I suppose this will calculate thirteenOrphans hand' all over again, slight inneficiency in that sense
             -- as we are checking it twice... Except... Laziness probably saves us from that!
             let handContext = getMinimalHandContext hand' sevenPairs
             handContext' <- do
-                let hasWind = hand' & (filter isWind) & (/= [])
+                let hasWind = hand' & filter isWind & (/= [])
                 if not sevenPairs
-                    then pure handContext >>= (if hasWind then addWindContext else pure) >>= addRiichiContext >>= addTsumoContext >>= addWaitContext
-                    else pure handContext >>= addRiichiContext >>= addTsumoContext
+                    then (if hasWind then addWindContext else pure) handContext >>= addRiichiContext >>= addTsumoContext >>= addWaitContext
+                    else addRiichiContext handContext >>= addTsumoContext
             (maybeIh', handContext'') <- addClosedContext maybeIh handContext'
             let yakuContext = mkYakuContext hand' maybeIh' handContext''
             return $ Context maybeIh' handContext'' (Left yakuContext)
diff --git a/src/Riichi/Display.hs b/src/Riichi/Display.hs
--- a/src/Riichi/Display.hs
+++ b/src/Riichi/Display.hs
@@ -7,10 +7,10 @@
 module Riichi.Display where
 
 import ColourStrings
-import Control.Monad (forM)
+import Control.Monad (forM, forM_, when)
 import Control.Monad.Trans
 import Data.Function
-import Data.List (intersperse, sort)
+import Data.List (intercalate, intersperse, sort)
 import Data.Monoid (getSum)
 import Riichi.Context
 import Riichi.Meld
@@ -30,64 +30,59 @@
             putStrLn "🀀 🀁 🀂 🀃 "
             putStrLn "Assuming East round and East seat."
             let num = length ihs
-            if num >= 1
-                then do
-                    if num == 1
-                        then putStrLn $ "Found 1 way to interpret this hand:\n"
-                        else putStrLn $ "Found " ++ show num ++ " ways to interpret this hand:\n"
-                    _ <- forM ihs $ \ih -> do
-                        let handString = showInterpretedHand ih
-                        let handContext = getMinimalHandContext hand False
-                        maybeYakumanContext <- mkYakumanContext hand (Just ih) (Just True)
-                        let context = case maybeYakumanContext of
-                                Nothing ->
-                                    let yakuContext = mkYakuContext hand (Just ih) handContext
-                                     in (Context (Just ih) handContext (Left yakuContext))
-                                Just yakumanContext -> (Context (Just ih) handContext (Right yakumanContext))
-                        let string = formContextString context
-                        let hanOrYakumans = getContextHansOrYakumans context
-                        case hanOrYakumans of
-                            Left (hanClosed, hanOpen) ->
-                                putStrLn $
-                                    handString
-                                        ++ "\n"
-                                        ++ string
-                                        ++ "\t\t"
-                                        ++ toGreen (show (getSum hanClosed))
-                                        ++ " Han total if closed, "
-                                        ++ toGreen (show (getSum hanOpen))
-                                        ++ " if open\n"
-                            Right yakumans -> putStrLn $ handString ++ "\n" ++ string ++ "\t\t" ++ toGreen (show yakumans) ++ " Yakuman total\n"
-                    return ()
-                else return ()
-            if (chiitoitsu hand) || (thirteenOrphans hand)
+            when (num >= 1) $ do
+                if num == 1
+                    then putStrLn "Found 1 way to interpret this hand:\n"
+                    else putStrLn $ "Found " ++ show num ++ " ways to interpret this hand:\n"
+                forM_ ihs $ \ih -> do
+                    let handString = showInterpretedHand ih
+                    let handContext = getMinimalHandContext hand False
+                    maybeYakumanContext <- mkYakumanContext hand (Just ih) (Just True)
+                    let context = case maybeYakumanContext of
+                            Nothing ->
+                                let yakuContext = mkYakuContext hand (Just ih) handContext
+                                 in Context (Just ih) handContext (Left yakuContext)
+                            Just yakumanContext -> Context (Just ih) handContext (Right yakumanContext)
+                    let string = formContextString context
+                    let hanOrYakumans = getContextHansOrYakumans context
+                    case hanOrYakumans of
+                        Left (hanClosed, hanOpen) ->
+                            putStrLn $
+                                handString
+                                    ++ "\n"
+                                    ++ string
+                                    ++ "\t\t"
+                                    ++ toGreen (show (getSum hanClosed))
+                                    ++ " Han total if closed, "
+                                    ++ toGreen (show (getSum hanOpen))
+                                    ++ " if open\n"
+                        Right yakumans -> putStrLn $ handString ++ "\n" ++ string ++ "\t\t" ++ toGreen (show yakumans) ++ " Yakuman total\n"
+            if chiitoitsu hand || thirteenOrphans hand
                 then do
                     if num == 0
                         then putStrLn "This hand can be interpreted as:\n"
                         else putStrLn "This hand can also be interpreted as:\n"
-                    let handString = hand & sort & map show & intersperse ", " & concat
+                    let handString = intercalate ", " (hand & sort & map show)
                     let handContext = getMinimalHandContext hand True
                     maybeYakumanContext <- mkYakumanContext hand Nothing (Just True)
                     let context = case maybeYakumanContext of
                             Nothing ->
                                 let yakuContext = mkYakuContext hand Nothing handContext
-                                 in (Context Nothing handContext (Left yakuContext))
-                            Just yakumanContext -> (Context Nothing handContext (Right yakumanContext))
+                                 in Context Nothing handContext (Left yakuContext)
+                            Just yakumanContext -> Context Nothing handContext (Right yakumanContext)
                     let string = formContextString context
                     let hanOrYakumans = getContextHanOrYakumans context
                     putStrLn $ case hanOrYakumans of
                         Left han -> handString ++ "\n" ++ string ++ "\t\t" ++ toGreen (show (getSum han)) ++ " Han total, closed by definition\n"
                         Right yakumans -> handString ++ "\n" ++ string ++ "\t\t" ++ toGreen (show yakumans) ++ " Yakuman total\n"
                 else
-                    if num == 0
-                        then putStrLn $ toRed "This hand is not valid"
-                        else return ()
+                    Control.Monad.when (num == 0) $ putStrLn $ toRed "This hand is not valid"
 
 -- | Implements the "waits" command for the CLI.
 displayHandWaits :: Hand -> IO ()
 displayHandWaits hand = do
     let waits = getWaits hand
-    putStrLn $ "Waits are: " ++ (waits & map show & intersperse ", " & concat)
+    putStrLn $ "Waits are: " ++ intercalate ", " (waits & map show)
 
 -- | Implements the "score" command for the CLI.
 displayHandScore :: Hand -> IO ()
@@ -101,38 +96,40 @@
             let closure = isClosed handContext
             let hanOrYakumans = getContextHanOrYakumans context
             case hanOrYakumans of
-                Left han -> do
-                    let fu = getContextFu context
-                    let name = hanToHandName han
-                    putStrLn $
-                        "\tYaku:\n"
-                            ++ string
-                            ++ "\t\t"
-                            ++ openClosed
-                            ++ toGreen (show (getSum han))
-                            ++ " Han total, with "
-                            ++ toBlue (show fu)
-                            ++ " Fu\n"
-                            ++ "\n\t"
-                            ++ toGreen (show (getScore han fu True tsumo))
-                            ++ " points for Dealer, "
-                            ++ toGreen (show (getScore han fu False tsumo))
-                            ++ " points for Non-Dealer"
-                            ++ ( if name /= ""
-                                    then
-                                        " ("
-                                            ++ toMagenta name
-                                            ++ ")."
-                                    else ""
-                               )
-                  where
-                    name = hanToHandName han
-                    openClosed = if closure then "Closed hand: " else "Open hand: "
+                Left han ->
+                    if getContextDora context == getSum han
+                        then
+                            putStrLn $ "\n\t" ++ toRed "Hand has no yaku!"
+                        else do
+                            let fu = getContextFu context
+                            let name = hanFuToHandName han fu
+                            let openClosed = if closure then "Closed hand: " else "Open hand: "
+                            putStrLn $
+                                "\tYaku:\n"
+                                    ++ string
+                                    ++ "\t\t"
+                                    ++ openClosed
+                                    ++ toGreen (show (getSum han))
+                                    ++ " Han total, with "
+                                    ++ toBlue (show fu)
+                                    ++ " Fu\n"
+                                    ++ "\n\t"
+                                    ++ toGreen (show (getScore han fu True tsumo))
+                                    ++ " points for Dealer, "
+                                    ++ toGreen (show (getScore han fu False tsumo))
+                                    ++ " points for Non-Dealer"
+                                    ++ ( if name /= ""
+                                            then
+                                                " ("
+                                                    ++ toMagenta name
+                                                    ++ ")."
+                                            else ""
+                                       )
                 Right yakumans ->
                     putStrLn $
                         string
                             ++ "\t\t"
-                            ++ toGreen (show (yakumans))
+                            ++ toGreen (show yakumans)
                             ++ " Yakuman total\n"
                             ++ "\n\t"
                             ++ toGreen (show (yakumans * 48000))
diff --git a/src/Riichi/Meld.hs b/src/Riichi/Meld.hs
--- a/src/Riichi/Meld.hs
+++ b/src/Riichi/Meld.hs
@@ -21,7 +21,7 @@
 | eg: 123p parses to 1 Pin, 2 Pin, 3 Pin; rgNE parses to Red, Green, North, East
 -}
 mkHand :: String -> Hand
-mkHand tiles = tiles & words & (map readTileBlock) & concat
+mkHand tiles = concatMap readTileBlock (tiles & words)
 
 -- | Add dora (in the first argument) a the hand (in the second argument)
 addDora :: Hand -> Hand -> Hand
@@ -31,8 +31,8 @@
     tile <- hand'
     if doraTile == tile
         then return $ case tile of
-            (Honour x d) -> (Honour x (d + 1))
-            (Numeric s v d) -> (Numeric s v (d + 1))
+            (Honour x d) -> Honour x (d + 1)
+            (Numeric s v d) -> Numeric s v (d + 1)
         else
             return tile
 
@@ -54,38 +54,38 @@
 instance Eq Meld where
     (==) (Pon tile1 _) (Pon tile2 _) = tile1 == tile2
     (==) (Kan tile1 _) (Kan tile2 _) = tile1 == tile2
-    (==) (Chi tile1 tile2 tile3 _) (Chi tile1' tile2' tile3' _) = Set.fromList ([tile1, tile2, tile3]) == Set.fromList ([tile1', tile2', tile3'])
+    (==) (Chi tile1 tile2 tile3 _) (Chi tile1' tile2' tile3' _) = Set.fromList [tile1, tile2, tile3] == Set.fromList [tile1', tile2', tile3']
     (==) _ _ = False
 
 -- | Using the show instance for tile, show melds as "Open/Closed chi/pon/kan: tile tile tile (tile)"
 instance Show Meld where
-    show (Chi (Numeric suit v1 _) (Numeric _ v2 _) (Numeric _ v3 _) True) = "Open chi: " ++ ((map show $ sort [v1, v2, v3]) & concat) ++ " " ++ (show suit)
-    show (Chi (Numeric suit v1 _) (Numeric _ v2 _) (Numeric _ v3 _) False) = "Closed chi: " ++ ((map show $ sort [v1, v2, v3]) & concat) ++ " " ++ (show suit)
-    show (Pon (Numeric suit v1 _) True) = "Open pon: " ++ (v1 & show & repeat & (take 3) & concat) ++ " " ++ (show suit)
-    show (Pon (Numeric suit v1 _) False) = "Closed pon: " ++ (v1 & show & repeat & (take 3) & concat) ++ " " ++ (show suit)
-    show (Kan (Numeric suit v1 _) True) = "Open kan: " ++ (v1 & show & repeat & (take 4) & concat) ++ " " ++ (show suit)
-    show (Kan (Numeric suit v1 _) False) = "Closed kan: " ++ (v1 & show & repeat & (take 4) & concat) ++ " " ++ (show suit)
-    show (Pon (tile) True) = "Open pon: " ++ (tile & show & repeat & (take 3) & concat)
-    show (Pon (tile) False) = "Closed pon: " ++ (tile & show & repeat & (take 3) & concat)
-    show (Kan (tile) True) = "Open kan: " ++ (tile & show & repeat & (take 4) & concat)
-    show (Kan (tile) False) = "Closed kan: " ++ (tile & show & repeat & (take 4) & concat)
+    show (Chi (Numeric suit v1 _) (Numeric _ v2 _) (Numeric _ v3 _) True) = "Open chi: " ++ concatMap show (sort [v1, v2, v3]) ++ " " ++ show suit
+    show (Chi (Numeric suit v1 _) (Numeric _ v2 _) (Numeric _ v3 _) False) = "Closed chi: " ++ concatMap show (sort [v1, v2, v3]) ++ " " ++ show suit
+    show (Pon (Numeric suit v1 _) True) = "Open pon: " ++ (replicate 3 (v1 & show) & concat) ++ " " ++ show suit
+    show (Pon (Numeric suit v1 _) False) = "Closed pon: " ++ (replicate 3 (v1 & show) & concat) ++ " " ++ show suit
+    show (Kan (Numeric suit v1 _) True) = "Open kan: " ++ (replicate 4 (v1 & show) & concat) ++ " " ++ show suit
+    show (Kan (Numeric suit v1 _) False) = "Closed kan: " ++ (replicate 4 (v1 & show) & concat) ++ " " ++ show suit
+    show (Pon tile True) = "Open pon: " ++ (replicate 3 (tile & show) & concat)
+    show (Pon tile False) = "Closed pon: " ++ (replicate 3 (tile & show) & concat)
+    show (Kan tile True) = "Open kan: " ++ (replicate 4 (tile & show) & concat)
+    show (Kan tile False) = "Closed kan: " ++ (replicate 4 (tile & show) & concat)
 
 -- | Check if all elements of a list of equatable elements are equal
 allEqual :: (Eq a) => [a] -> Bool
 allEqual [] = True
 allEqual [_] = True
-allEqual (x : y : ys) = (x == y) && (allEqual (y : ys))
+allEqual (x : y : ys) = (x == y) && allEqual (y : ys)
 
 -- | Check if all elements of a list of equatable elements are different
 allDifferent :: (Eq a) => [a] -> Bool
 allDifferent [] = True
 allDifferent [_] = True
-allDifferent (x : xs) = (not (x `elem` xs)) && (allDifferent xs)
+allDifferent (x : xs) = notElem x xs && allDifferent xs
 
 -- | Check if three tiles form a chi (a sequence)
 isChi :: Tile -> Tile -> Tile -> Bool
 isChi (Numeric s1 v1 _) (Numeric s2 v2 _) (Numeric s3 v3 _) =
-    (allEqual [s1, s2, s3]) && (Set.fromList (map (subtract m) [v1, v2, v3]) == Set.fromList ([0, 1, 2]))
+    allEqual [s1, s2, s3] && (Set.fromList (map (subtract m) [v1, v2, v3]) == Set.fromList [0, 1, 2])
   where
     m = minimum [v1, v2, v3]
 isChi _ _ _ = False
@@ -116,7 +116,7 @@
 
 -- | Check if a meld is a chi
 meldIsChi :: Meld -> Bool
-meldIsChi (Chi _ _ _ _) = True
+meldIsChi (Chi{}) = True
 meldIsChi _ = False
 
 -- | Check if a meld is a pon
@@ -132,7 +132,7 @@
 {- | Get the "base" of a Meld. For a chi this is the lowest value. Otherwise it is the common value or
 | honour instance of the tiles.
 -}
-getMeldBase :: Meld -> Either Integer Honour
+getMeldBase :: Meld -> Either Value Honour
 getMeldBase (Chi (Numeric _ v1 _) (Numeric _ v2 _) (Numeric _ v3 _) _) = Left (minimum [v1, v2, v3])
 getMeldBase (Pon (Numeric _ v1 _) _) = Left v1
 getMeldBase (Kan (Numeric _ v1 _) _) = Left v1
@@ -152,7 +152,7 @@
 getPairSuit (Pair (Numeric suit _ _)) = Left suit
 getPairSuit (Pair (Honour honour _)) = Right honour
 
--- | Given a hand, return all the possible ways of interpreting it as a sequence of melds
+-- | Given a hand, return all the possible ways of pulling out chis and pons, in increasing order of length
 form3Melds :: Hand -> [[Meld]]
 form3Melds [] = [[]]
 form3Melds [_] = [[]]
@@ -160,46 +160,91 @@
 form3Melds hand@(tile : tiles) =
     let
         -- Form all possible sets of melds with the first meld including the first tile:
-        -- triples = tiles & tails & init & (map (\x -> (head x, tail x))) & (map (\(tile2, final_tiles) -> [[tile, tile2, tile3] | tile3 <- final_tiles])) & concat
         triples = do
             (tile2 : rest) <- tiles & tails & init
             tile3 <- rest
             return [tile, tile2, tile3]
 
         possible_melds =
-            ( map
-                ( \triple@(tile1 : tile2 : tile3 : _) ->
-                    if (isChi tile1 tile2 tile3)
-                        then map ((Chi tile1 tile2 tile3 False) :) (form3Melds (hand \\ triple))
-                        else
-                            if (isPon tile1 tile2 tile3)
-                                then map ((Pon tile1 False) :) (form3Melds (hand \\ triple))
-                                else []
-                )
-                triples
-                & concat
-            )
-                & map sort
-                & sort
-                & group
-                & (map head)
+            form3Melds (tail hand)
+                ++ concat
+                    ( do
+                        triple@(tile1 : tile2 : tile3 : _) <- triples
+                        let nextMelds = form3Melds (hand \\ triple)
+                        if isChi tile1 tile2 tile3
+                            then
+                                return $ map (Chi tile1 tile2 tile3 False :) nextMelds
+                            else
+                                if isPon tile1 tile2 tile3
+                                    then
+                                        return $ map (Pon tile1 False :) nextMelds
+                                    else
+                                        return []
+                    )
      in
-        possible_melds ++ (form3Melds $ tail hand)
+        concatMap
+            (((map head . group) . sort) . map sort)
+            ( possible_melds
+                & sortBy (\x y -> compare (length x) (length y))
+                & groupBy (\x y -> length x == length y)
+            )
 
+-- | Given a hand, return all the possible ways of interpreting it as a sequence of melds
+formMelds :: Hand -> [[Meld]]
 formMelds hand = do
     (kans, hand') <- findKans hand
     melds <- form3Melds hand'
     return $ kans ++ melds
 
--- if possible_melds == []
---     then formMelds (tail hand)
---     else possible_melds
+-- | Given a hand, return all the possible ways of spliting the entire hand into chis, pons and kans
+formComplete3Melds :: Hand -> [[Meld]]
+formComplete3Melds [] = [[]]
+formComplete3Melds [_] = [[]]
+formComplete3Melds hand@(tile : tiles) =
+    let
+        -- Form all possible sets of melds with the first meld including the first tile:
+        triples = do
+            (tile2 : rest) <- tiles & tails & init
+            tile3 <- rest
+            return [tile, tile2, tile3]
 
+        possible_melds =
+            ( concat $ do
+                triple@(tile1 : tile2 : tile3 : _) <- triples
+                let nextMelds = form3Melds (hand \\ triple)
+                if isChi tile1 tile2 tile3
+                    then
+                        return $ map (Chi tile1 tile2 tile3 False :) nextMelds
+                    else
+                        if isPon tile1 tile2 tile3
+                            then
+                                return $ map (Pon tile1 False :) nextMelds
+                            else
+                                return []
+            )
+     in
+        possible_melds
+            & filter (\x -> length x * 3 == length hand)
+            & map sort
+            & sort
+            & group
+            & map head
+
+-- | Given a hand, return all the possible ways of interpreting it as a sequence of melds
+formCompleteMelds :: Hand -> [[Meld]]
+formCompleteMelds hand = do
+    (kans, hand') <- findKans hand
+    melds <- formComplete3Melds hand'
+    let kans_melds = kans ++ melds
+    if length kans_melds == 4
+        then return kans_melds
+        else []
+
 -- | Count the tiles in a list of melds
 meldsLength :: [Meld] -> Int
 meldsLength [] = 0
-meldsLength ((Kan _ _) : rest) = 4 + (meldsLength rest)
-meldsLength (_ : rest) = 3 + (meldsLength rest)
+meldsLength ((Kan _ _) : rest) = 4 + meldsLength rest
+meldsLength (_ : rest) = 3 + meldsLength rest
 
 -- | Reverse form melds. Concatenate a list of melds back into a hand.
 concatMelds :: [Meld] -> Hand
@@ -214,9 +259,8 @@
     hand
         & sort
         & group
-        & (filter (\list -> 2 <= (length list)))
-        & (map head)
-        & (map (\tile -> (Pair tile, hand \\ [tile, tile])))
+        & filter (\list -> 2 <= length list)
+        & map ((\tile -> (Pair tile, hand \\ [tile, tile])) . head)
 
 -- | Find all the ways of pulling kans out of a hand. In each case pair the set of kans with what remains of the hand
 findKans :: Hand -> [([Meld], Hand)]
@@ -224,12 +268,11 @@
     hand
         & sort
         & group
-        & filter (\list -> 4 == (length list))
-        & map head
-        & map (\tile -> (Kan tile False))
+        & filter (\list -> 4 == length list)
+        & map ((`Kan` False) . head)
         & subsequences
         -- & tail
-        & map (\kans -> (kans, hand \\ (concat [tile & repeat & take 4 | Kan tile _ <- kans])))
+        & map (\kans -> (kans, hand \\ concat [replicate 4 tile | Kan tile _ <- kans]))
 
 -- interpretHand assumes the hand consists of a pair and 4 melds (chis pons or kans).
 -- An InterpretedHand can then be passed on to other functions to check for yakus.
@@ -246,25 +289,15 @@
         possible_pairs = hand & findPairs
         pairs_melds = do
             (pair, hand') <- possible_pairs
-            melds <- formMelds hand'
+            melds <- formCompleteMelds hand'
             return (pair, melds)
      in
-        -- pairs_kans_hands = do
-        --     (pair, hand') <- possible_pairs
-        --     (kans, hand'') <- findKans hand'
-        --     melds <- formMelds hand''
-        --     return (pair, kans ++ melds)
-        -- pairs_hands = do
-        --     (pair, hand') <- possible_pairs
-        --     melds <- formMelds hand'
-        --     return (pair, melds)
-
         pairs_melds
-            & (filter (\(_, melds) -> (length hand) == 2 + (meldsLength melds)))
+            & filter (\(_, melds) -> length hand == 2 + meldsLength melds)
 
 -- | Show a full interpreted hand
 showInterpretedHand :: InterpretedHand -> String
-showInterpretedHand (pair, melds) = (show pair) : (map show melds) & intersperse ", " & concat
+showInterpretedHand (pair, melds) = show pair : map show melds & intercalate ", "
 
 -- | Ask which meld was opened by ron. Return modified melds with that meld opened.
 getRonMeld :: [Meld] -> IO [Meld]
@@ -276,7 +309,7 @@
         then return melds
         else
             let index :: Int = input & read
-             in return $ (zip [0 ..] melds) & map (\(i, meld) -> if i == index then openMeld meld else meld)
+             in return $ zipWith (\i meld -> (if i == index then openMeld meld else meld)) [0 ..] melds
 
 {- | Ask which melds are open in a set of melds. Return modified melds with this data added. Opens the specified melds,
 | but if a meld is already open it stays that way. (This may change in the future)
@@ -286,5 +319,5 @@
     putStrLn "Which melds are open? (enter a string of indices, or leave blank if all closed): "
     sequence_ $ [("[" ++ show i ++ "]: " ++ (meld & show)) & putStrLn | (i :: Integer, meld) <- zip [0 ..] melds]
     input <- getLine
-    let indices :: [Int] = input & map return & (map read)
-    return $ (zip [0 ..] melds) & map (\(i, meld) -> if i `elem` indices then openMeld meld else meld)
+    let indices :: [Int] = map (read . return) input
+    return $ zipWith (\i meld -> (if i `elem` indices then openMeld meld else meld)) [0 ..] melds
diff --git a/src/Riichi/Scoring.hs b/src/Riichi/Scoring.hs
--- a/src/Riichi/Scoring.hs
+++ b/src/Riichi/Scoring.hs
@@ -11,6 +11,7 @@
 import Control.Monad.Writer
 import Data.Function ((&))
 import Data.Map qualified as M
+import Data.Maybe (fromMaybe)
 import Data.Monoid (Sum (..))
 import Riichi.Context
 import Riichi.Meld
@@ -25,7 +26,7 @@
 
 -- | Get the fu contributed by a meld (only pons and kans give fu)
 getMeldFu :: Meld -> Fu
-getMeldFu (Chi _ _ _ _) = 0
+getMeldFu (Chi{}) = 0
 getMeldFu (Pon (Numeric _ v _) True) = if v `elem` [1, 9] then 4 else 2
 getMeldFu (Pon (Honour _ _) True) = 4
 getMeldFu (Pon (Numeric _ v _) False) = if v `elem` [1, 9] then 8 else 4
@@ -45,31 +46,19 @@
         then case han of
             _
                 | han >= 13 -> 32000
-                | han >= 5 -> case M.lookup han manganToSanbaimanTableDealer of
-                    Just score -> score
-                    Nothing -> 0
+                | han >= 5 -> fromMaybe 0 (M.lookup han manganToSanbaimanTableDealer)
                 | otherwise ->
                     if tsumo
-                        then case M.lookup (han, fu) scoreTableTsumoDealer of
-                            Just score -> score
-                            Nothing -> 0
-                        else case M.lookup (han, fu) scoreTableRonDealer of
-                            Just score -> score
-                            Nothing -> 0
+                        then fromMaybe 0 (M.lookup (han, fu) scoreTableTsumoDealer)
+                        else fromMaybe 0 (M.lookup (han, fu) scoreTableRonDealer)
         else case han of
             _
                 | han >= 13 -> 24000
-                | han >= 5 -> case M.lookup han manganToSanbaimanTableNonDealer of
-                    Just score -> score
-                    Nothing -> 0
+                | han >= 5 -> fromMaybe 0 (M.lookup han manganToSanbaimanTableNonDealer)
                 | otherwise ->
                     if tsumo
-                        then case M.lookup (han, fu) scoreTableTsumoNonDealer of
-                            Just score -> score
-                            Nothing -> 0
-                        else case M.lookup (han, fu) scoreTableRonNonDealer of
-                            Just score -> score
-                            Nothing -> 0
+                        then fromMaybe 0 (M.lookup (han, fu) scoreTableTsumoNonDealer)
+                        else fromMaybe 0 (M.lookup (han, fu) scoreTableRonNonDealer)
 
 -- | Form the string describing the yaku, given a yaku context
 formYakuString :: YakuContext -> String
@@ -108,34 +97,34 @@
 getYakuHan :: YakuContext -> Han
 getYakuHan yakuContext@YakuContext{yakuHandContext = handContext@HandContext{riichi = riichiContext, dora}} =
     let
-        closedBonus = if (isClosed handContext == True) then 1 else 0
+        closedBonus = if isClosed handContext then 1 else 0
         hanWriter :: Writer Han () = do
-            when (isRiichi riichiContext) $ tell $ 1
-            when (isIppatsu riichiContext) $ tell $ 1
-            when (isMenzenTsumo yakuContext) $ tell $ 1
-            when (isChiitoitsu yakuContext) $ tell $ 2
-            when (isPinfu yakuContext) $ tell $ 1
-            when (isTanyao yakuContext) $ tell $ 1
-            when (isHaku yakuContext) $ tell $ 1
-            when (isHatsu yakuContext) $ tell $ 1
-            when (isChun yakuContext) $ tell $ 1
-            when (isSeatWind yakuContext) $ tell $ 1
-            when (isRoundWind yakuContext) $ tell $ 1
+            when (isRiichi riichiContext) $ tell 1
+            when (isIppatsu riichiContext) $ tell 1
+            when (isMenzenTsumo yakuContext) $ tell 1
+            when (isChiitoitsu yakuContext) $ tell 2
+            when (isPinfu yakuContext) $ tell 1
+            when (isTanyao yakuContext) $ tell 1
+            when (isHaku yakuContext) $ tell 1
+            when (isHatsu yakuContext) $ tell 1
+            when (isChun yakuContext) $ tell 1
+            when (isSeatWind yakuContext) $ tell 1
+            when (isRoundWind yakuContext) $ tell 1
             when (isSanshokuDoujun yakuContext) $ tell $ 1 + closedBonus
-            when (isSanshokuDoukou yakuContext) $ tell $ 2
-            when (isSanankou yakuContext) $ tell $ 2
+            when (isSanshokuDoukou yakuContext) $ tell 2
+            when (isSanankou yakuContext) $ tell 2
             when (isChinitsu yakuContext) $ tell $ 5 + closedBonus
             when (isHonitsu yakuContext) $ tell $ 2 + closedBonus
-            when (isToitoi yakuContext) $ tell $ 2
+            when (isToitoi yakuContext) $ tell 2
             when (isIttsuu yakuContext) $ tell $ 1 + closedBonus
-            when (isSankantsu yakuContext) $ tell $ 2
-            when (isShousangen yakuContext) $ tell $ 2
+            when (isSankantsu yakuContext) $ tell 2
+            when (isShousangen yakuContext) $ tell 2
             when (isRyanpeikou yakuContext) $ tell $ 3 * closedBonus
-            when (isIipeikou yakuContext) $ tell $ closedBonus
+            when (isIipeikou yakuContext) $ tell closedBonus
             when (isJunchan yakuContext) $ tell $ 2 + closedBonus
-            when (isHonroutou yakuContext) $ tell $ 2
+            when (isHonroutou yakuContext) $ tell 2
             when (isChanta yakuContext) $ tell $ 1 + closedBonus
-            tell $ fromInteger dora
+            tell $ Sum dora
         (_, han) = runWriter hanWriter
      in
         han
@@ -191,7 +180,7 @@
 -- | Get the open and closed han, or yakumans, of a context
 getContextHansOrYakumans :: Context -> Either (Han, Han) YakumanCount
 getContextHansOrYakumans (Context _ _ (Left yakuContext@YakuContext{yakuHandContext = handContext})) =
-    Left $
+    Left
         ( getYakuHan yakuContext{yakuHandContext = closeHandContext handContext}
         , getYakuHan yakuContext{yakuHandContext = openHandContext handContext}
         )
@@ -203,21 +192,21 @@
     let
         sw = seatWind $ wind c
         rw = roundWind $ wind c
-        goodWait = not $ (isRyanmanWait $ wait c) || (isShanponWait $ wait c)
+        goodWait = not $ isRyanmanWait (wait c) || isShanponWait (wait c)
         tsumo = isTsumo c
         closure = isClosed c
         meldsFu = melds & map getMeldFu & sum
         waitFu = if goodWait then 2 else 0
         yakuhaiFu =
-            (if (tile & isDragon) then 2 else 0)
-                + (if (tile == (Honour (Wind rw) 0)) then 2 else 0)
-                + (if (tile == (Honour (Wind sw) 0)) then 2 else 0)
-        ronClosedFu = if (not tsumo) && closure then 10 else 0
+            (if tile & isDragon then 2 else 0)
+                + (if tile == Honour (Wind rw) 0 then 2 else 0)
+                + (if tile == Honour (Wind sw) 0 then 2 else 0)
+        ronClosedFu = if not tsumo && closure then 10 else 0
         tsumoFu = if tsumo then 2 else 0
      in
         roundUp (20 + meldsFu + waitFu + yakuhaiFu + ronClosedFu + tsumoFu)
   where
-    roundUp n = last ([120, 110 .. 10] & filter (>= n))
+    roundUp n = last ([170, 160 .. 10] & filter (>= n))
 
 -- | Get the fu for a context.
 getContextFu :: Context -> Fu
@@ -439,13 +428,15 @@
         ]
 
 -- | Get the name for a 5+ han hand
-hanToHandName :: Han -> String
-hanToHandName 5 = "Mangan"
-hanToHandName 6 = "Haneman"
-hanToHandName 7 = "Haneman"
-hanToHandName 8 = "Baiman"
-hanToHandName 9 = "Baiman"
-hanToHandName 10 = "Baiman"
-hanToHandName 11 = "Sanbaiman"
-hanToHandName 12 = "Sanbaiman"
-hanToHandName n = if n >= 13 then "Counted Yakuman" else ""
+hanFuToHandName :: Han -> Fu -> String
+hanFuToHandName 3 fu = if fu >= 70 then "Mangan" else ""
+hanFuToHandName 4 fu = if fu >= 40 then "Mangan" else ""
+hanFuToHandName 5 _ = "Mangan"
+hanFuToHandName 6 _ = "Haneman"
+hanFuToHandName 7 _ = "Haneman"
+hanFuToHandName 8 _ = "Baiman"
+hanFuToHandName 9 _ = "Baiman"
+hanFuToHandName 10 _ = "Baiman"
+hanFuToHandName 11 _ = "Sanbaiman"
+hanFuToHandName 12 _ = "Sanbaiman"
+hanFuToHandName n _ = if n >= 13 then "Counted Yakuman" else ""
diff --git a/src/Riichi/Tile.hs b/src/Riichi/Tile.hs
--- a/src/Riichi/Tile.hs
+++ b/src/Riichi/Tile.hs
@@ -7,7 +7,7 @@
 module Riichi.Tile where
 
 import Data.Function
-import Data.List (intersperse)
+import Data.List (intercalate, intersperse)
 
 {- |
 Tile data type. Can be an honour tile or a numeric tile. Dora is tracked
@@ -16,13 +16,13 @@
 data Tile = Honour Honour Dora | Numeric Suit Value Dora deriving (Ord)
 
 -- | Simple type alias. Tracks dora value for a tile. Note red five is represented as dora 1.
-type Dora = Integer
+type Dora = Int
 
 -- | Type alias for the value of a Numeric tile.
-type Value = Integer
+type Value = Int
 
 -- | An honour tile is a dragon or a wind
-data Honour = Dragon (Dragon) | Wind (Wind) deriving (Show, Eq, Ord)
+data Honour = Dragon Dragon | Wind Wind deriving (Show, Eq, Ord)
 
 -- | Dragon enum
 data Dragon = White | Green | Red deriving (Show, Eq, Ord)
@@ -39,16 +39,16 @@
 -}
 instance Read Tile where
     readsPrec :: Int -> ReadS Tile
-    readsPrec _ (x : []) = [(tile, [])]
+    readsPrec _ [x] = [(tile, [])]
       where
         tile = case x of
-            'N' -> (Honour $ Wind $ North) 0
-            'E' -> (Honour $ Wind $ East) 0
-            'S' -> (Honour $ Wind $ South) 0
-            'W' -> (Honour $ Wind $ West) 0
-            'r' -> (Honour $ Dragon $ Red) 0
-            'g' -> (Honour $ Dragon $ Green) 0
-            'w' -> (Honour $ Dragon $ White) 0
+            'N' -> (Honour $ Wind North) 0
+            'E' -> (Honour $ Wind East) 0
+            'S' -> (Honour $ Wind South) 0
+            'W' -> (Honour $ Wind West) 0
+            'r' -> (Honour $ Dragon Red) 0
+            'g' -> (Honour $ Dragon Green) 0
+            'w' -> (Honour $ Dragon White) 0
     readsPrec _ (x : y : _) = do
         let ((value, dora), suit) =
                 ( case x of
@@ -80,7 +80,7 @@
             's' -> (init string, "s ")
             _ -> (string, " ")
      in
-        stripped & map (\c -> [c]) & intersperse separator & concat & (++ separator) & words & map read
+        map pure stripped & intercalate separator & (++ separator) & words & map read
 
 -- | Implements an inverse to read
 instance Show Tile where
@@ -94,15 +94,15 @@
     show (Numeric Pin 5 d) = if d == 0 then "5p" else "5p*"
     show (Numeric Man 5 d) = if d == 0 then "5m" else "5m*"
     show (Numeric Sou 5 d) = if d == 0 then "5s" else "5s*"
-    show (Numeric Pin n _) = (show n) ++ "p"
-    show (Numeric Man n _) = (show n) ++ "m"
-    show (Numeric Sou n _) = (show n) ++ "s"
+    show (Numeric Pin n _) = show n ++ "p"
+    show (Numeric Man n _) = show n ++ "m"
+    show (Numeric Sou n _) = show n ++ "s"
 
 {- | Almost identical to what would result from deriving Eq on Tile, except we choose to
 | ignore the Dora value
 -}
 instance Eq Tile where
-    (==) (Honour honour _) (Honour honour' _) = (honour == honour')
+    (==) (Honour honour _) (Honour honour' _) = honour == honour'
     (==) (Numeric suit value _) (Numeric suit' value' _) = (suit == suit') && (value == value')
     (==) _ _ = False
 
diff --git a/src/Riichi/Waits.hs b/src/Riichi/Waits.hs
--- a/src/Riichi/Waits.hs
+++ b/src/Riichi/Waits.hs
@@ -8,6 +8,7 @@
 
 import Data.Function
 import Data.List
+import GHC.IO.Handle (noNewlineTranslation)
 import Riichi.Meld
 import Riichi.Tile
 
@@ -21,7 +22,7 @@
             let pairs = findPairs hand
                 sevenPairsWait =
                     ( if length pairs == 6
-                        then case (hand & sort & group & filter (\gp -> 1 == length gp)) of
+                        then case hand & sort & group & filter (\gp -> 1 == length gp) of
                             [[tile]] -> [tile]
                             _ -> []
                         else []
@@ -30,7 +31,7 @@
                 orphansWaits =
                     if length hand == 13
                         then do
-                            let orphans = (mkHand "1p 9p 1s 9s 1m 9m N E S W r g w")
+                            let orphans = mkHand "1p 9p 1s 9s 1m 9m N E S W r g w"
                             let difference = hand \\ orphans
                             case difference of
                                 [] -> orphans
@@ -41,7 +42,7 @@
                 -- If we have four melds already, a single remaning tile can wait for a pair
                 possibleMelds = formMelds hand
                 fourMelds = possibleMelds & filter (\melds -> length melds == 4)
-                fourMeldsWaits = fourMelds & map (concatMelds) & map (hand \\) & filter (\diff -> length diff == 1) & concat
+                fourMeldsWaits = map ((hand \\) . concatMelds) fourMelds & filter (\diff -> length diff == 1) & concat
                 -- Finally, we might be waiting with three melds and a pair
                 threeMeldWaits = concat $ do
                     (pair, hand') <- findPairs hand
@@ -49,7 +50,7 @@
                     if length melds /= 3
                         then return []
                         else
-                            let diff = hand' \\ (concatMelds melds)
+                            let diff = hand' \\ concatMelds melds
                              in if length diff /= 2
                                     then return []
                                     else let [a, b] = diff in return (meldWait a b)
diff --git a/src/Riichi/Yaku.hs b/src/Riichi/Yaku.hs
--- a/src/Riichi/Yaku.hs
+++ b/src/Riichi/Yaku.hs
@@ -1,3 +1,5 @@
+{- HLINT ignore "Redundant bracket" -}
+
 {- |
 Module      : Riichi.Yaku
 Description : Methods for detecting the various yaku conditions
@@ -21,7 +23,7 @@
 
 -- | Check a hand for tanyao, aka all simples
 tanyao :: Hand -> Bool
-tanyao hand = hand & (map isSimple) & and
+tanyao = all isSimple
 
 {- | Check if a hand is composed entirely of unique pairs.
 Note this doesn't check the hand has the right size to be seven pairs.
@@ -39,13 +41,13 @@
     (length hand == 14)
         && ( Set.fromList hand
                 == Set.fromList
-                    [ (Honour $ Dragon $ Red) 0
-                    , (Honour $ Dragon $ White) 0
-                    , (Honour $ Dragon $ Green) 0
-                    , (Honour $ Wind $ North) 0
-                    , (Honour $ Wind $ South) 0
-                    , (Honour $ Wind $ East) 0
-                    , (Honour $ Wind $ West) 0
+                    [ (Honour $ Dragon Red) 0
+                    , (Honour $ Dragon White) 0
+                    , (Honour $ Dragon Green) 0
+                    , (Honour $ Wind North) 0
+                    , (Honour $ Wind South) 0
+                    , (Honour $ Wind East) 0
+                    , (Honour $ Wind West) 0
                     , (Numeric Pin 1) 0
                     , (Numeric Pin 9) 0
                     , (Numeric Man 1) 0
@@ -62,9 +64,9 @@
         & ( filter
                 ( \meld ->
                     meld
-                        `elem` [ Pon ((Honour $ Dragon $ Red) 0) False
-                               , Pon ((Honour $ Dragon $ Green) 0) False
-                               , Pon ((Honour $ Dragon $ White) 0) False
+                        `elem` [ Pon ((Honour $ Dragon Red) 0) False
+                               , Pon ((Honour $ Dragon Green) 0) False
+                               , Pon ((Honour $ Dragon White) 0) False
                                ]
                 )
           )
@@ -74,33 +76,41 @@
 checkPon :: Tile -> InterpretedHand -> Bool
 checkPon tile (_, melds) = Pon tile False `elem` melds
 
+-- | Check for the presence of a kan in an interpreted hand.
+checkKan :: Tile -> InterpretedHand -> Bool
+checkKan tile (_, melds) = Kan tile False `elem` melds
+
+-- | Check for the presence of a pon or kan in an interpreted hand.
+checkPonOrKan :: Tile -> InterpretedHand -> Bool
+checkPonOrKan t ih = (checkPon t ih) || (checkKan t ih)
+
 -- | Check for the presence of a white dragon triplet in an interpreted hand.
 haku :: InterpretedHand -> Bool
-haku = checkPon ((Honour $ Dragon $ White) 0)
+haku = checkPonOrKan ((Honour $ Dragon White) 0)
 
 -- | Check for the presence of a green dragon triplet in an interpreted hand.
 hatsu :: InterpretedHand -> Bool
-hatsu = checkPon ((Honour $ Dragon $ Green) 0)
+hatsu = checkPonOrKan ((Honour $ Dragon Green) 0)
 
 -- | Check for the presence of a red dragon triplet in an interpreted hand.
 chun :: InterpretedHand -> Bool
-chun = checkPon ((Honour $ Dragon $ Red) 0)
+chun = checkPonOrKan ((Honour $ Dragon Red) 0)
 
 -- | Check for the presence of a north wind triplet in an interpreted hand.
 checkNorth :: InterpretedHand -> Bool
-checkNorth = checkPon ((Honour $ Wind $ North) 0)
+checkNorth = checkPonOrKan ((Honour $ Wind North) 0)
 
 -- | Check for the presence of a east wind triplet in an interpreted hand.
 checkEast :: InterpretedHand -> Bool
-checkEast = checkPon ((Honour $ Wind $ East) 0)
+checkEast = checkPonOrKan ((Honour $ Wind East) 0)
 
 -- | Check for the presence of a south wind triplet in an interpreted hand.
 checkSouth :: InterpretedHand -> Bool
-checkSouth = checkPon ((Honour $ Wind $ South) 0)
+checkSouth = checkPonOrKan ((Honour $ Wind South) 0)
 
 -- | Check for the presence of a west wind triplet in an interpreted hand.
 checkWest :: InterpretedHand -> Bool
-checkWest = checkPon ((Honour $ Wind $ West) 0)
+checkWest = checkPonOrKan ((Honour $ Wind West) 0)
 
 -- | Check for the presence of a given wind triplet in an interpreted hand.
 checkWind :: Wind -> InterpretedHand -> Bool
@@ -152,7 +162,7 @@
 
 -- | Check if a hand is all triplets
 toitoi :: InterpretedHand -> Bool
-toitoi (_, melds) = melds & (map (\meld -> meldIsPon meld || meldIsKan meld)) & and
+toitoi (_, melds) = all (\meld -> meldIsPon meld || meldIsKan meld) melds
 
 -- | Check if a hand has 1-9 in a single suit
 ittsuu :: InterpretedHand -> Bool
@@ -238,33 +248,33 @@
 
 -- | Check for half outside hand
 chanta :: InterpretedHand -> Bool
-chanta (Pair tile, melds) = (melds & map getMeldBase & lefts & filter (\x -> x /= 1 && x /= 7)) == [] && (not $ isSimple tile)
+chanta (Pair tile, melds) = not (any (\x -> x /= 1 && x /= 7) (melds & map getMeldBase & lefts)) && not (isSimple tile)
 
 -- | Check for fully outside hand (chanta + no honnours)
 junchan :: InterpretedHand -> Bool
-junchan ih@(Pair tile, melds) = (isNumeric tile) && (melds & map getMeldBase & rights) == [] && (chanta ih)
+junchan ih@(Pair tile, melds) = (isNumeric tile) && null (melds & map getMeldBase & rights) && (chanta ih)
 
 -- | Check for all terminals and honours
 honroutou :: Hand -> Bool
-honroutou hand = hand & map (\tile -> isHonour tile || isTerminal tile) & and
+honroutou = all (\tile -> isHonour tile || isTerminal tile)
 
 {- | Check for all honours. Yakuman.
 Does not check that the hand is valid to begin with.
 -}
 tsuuiisou :: Hand -> Bool
-tsuuiisou hand = hand & map isHonour & and
+tsuuiisou = all isHonour
 
 {- | Check for all terminals. Yakuman.
 Does not check that the hand is valid to begin with.
 -}
 chinroutou :: Hand -> Bool
-chinroutou hand = hand & map isTerminal & and
+chinroutou = all isTerminal
 
 {- | Check for all green. Yakuman.
 Does not check that the hand is valid to begin with.
 -}
 ryuuiisou :: Hand -> Bool
-ryuuiisou hand = hand & map isGreen & and
+ryuuiisou = all isGreen
   where
     isGreen (Numeric Sou v _) = (v `elem` [2, 3, 4, 6, 8])
     isGreen (Honour (Dragon Green) _) = True
@@ -291,9 +301,9 @@
 -- | Check for pinfu. Takes the hand, the seat wind, round wind, whether the wait was ryanman, and whether it is closed (in that order).
 pinfu :: InterpretedHand -> Wind -> Wind -> Bool -> Bool -> Bool
 pinfu (Pair tile, melds) seatWind roundWind ryanmanWait closedHand =
-    (melds & filter (not . meldIsChi)) == []
+    (all meldIsChi melds)
         && closedHand
-        && (not $ isDragon tile)
+        && not (isDragon tile)
         && (tile /= (Honour (Wind seatWind) 0))
         && (tile /= (Honour (Wind roundWind) 0))
         && ryanmanWait
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -31,10 +31,8 @@
         , testCase "Single tile read test" $
             ((read "0m" :: Tile) == (read "5m" :: Tile))
                 && (read "r" == Honour (Dragon Red) 1) @?= True
-        , testCase "Multi tile read test 1" $
-            (readTileBlock "123p" @?= [Numeric Pin 1 0, Numeric Pin 2 0, Numeric Pin 3 0])
-        , testCase "Multi tile read test 2" $
-            (readTileBlock "rwN" @?= [Honour (Dragon Red) 0, Honour (Dragon White) 0, Honour (Wind North) 0])
+        , testCase "Multi tile read test 1" (readTileBlock "123p" @?= [Numeric Pin 1 0, Numeric Pin 2 0, Numeric Pin 3 0])
+        , testCase "Multi tile read test 2" (readTileBlock "rwN" @?= [Honour (Dragon Red) 0, Honour (Dragon White) 0, Honour (Wind North) 0])
         ]
 
 meldsTests :: TestTree
@@ -60,7 +58,7 @@
                 hand = mkHand "222m 333m 444m 555m 77p"
                 ihs = interpretHand hand
              in
-                (length ihs) @?= 3
+                length ihs @?= 3
         ]
 
 scoringTests :: TestTree
@@ -87,19 +85,19 @@
 showTests =
     testGroup
         "Show test group"
-        [ testCase "Tile show test 1" $ (show $ (read $ "1p" :: Tile)) @?= "1p"
-        , testCase "Tile show test 2" $ (show $ (read $ "2m" :: Tile)) @?= "2m"
-        , testCase "Tile show test 3" $ (show $ (read $ "3s" :: Tile)) @?= "3s"
-        , testCase "Tile show test 4" $ (show $ (read $ "r" :: Tile)) @?= "r"
-        , testCase "Tile show test 5" $ (show $ (read $ "g" :: Tile)) @?= "g"
-        , testCase "Tile show test 6" $ (show $ (read $ "w" :: Tile)) @?= "w"
-        , testCase "Tile show test 7" $ (show $ (read $ "N" :: Tile)) @?= "N"
-        , testCase "Tile show test 8" $ (show $ (read $ "S" :: Tile)) @?= "S"
-        , testCase "Tile show test 9" $ (show $ (read $ "E" :: Tile)) @?= "E"
-        , testCase "Tile show test 10" $ (show $ (read $ "W" :: Tile)) @?= "W"
-        , testCase "Tile show test 11" $ (show $ (read $ "0p" :: Tile)) @?= "5p*"
+        [ testCase "Tile show test 1" $ show (read "1p" :: Tile) @?= "1p"
+        , testCase "Tile show test 2" $ show (read "2m" :: Tile) @?= "2m"
+        , testCase "Tile show test 3" $ show (read "3s" :: Tile) @?= "3s"
+        , testCase "Tile show test 4" $ show (read "r" :: Tile) @?= "r"
+        , testCase "Tile show test 5" $ show (read "g" :: Tile) @?= "g"
+        , testCase "Tile show test 6" $ show (read "w" :: Tile) @?= "w"
+        , testCase "Tile show test 7" $ show (read "N" :: Tile) @?= "N"
+        , testCase "Tile show test 8" $ show (read "S" :: Tile) @?= "S"
+        , testCase "Tile show test 9" $ show (read "E" :: Tile) @?= "E"
+        , testCase "Tile show test 10" $ show (read "W" :: Tile) @?= "W"
+        , testCase "Tile show test 11" $ show (read "0p" :: Tile) @?= "5p*"
         , testCase "Hand show test" $
-            (showInterpretedHand $ (head $ interpretHand $ (mkHand "123p 456m 789s NNN rr")))
+            showInterpretedHand (head $ interpretHand (mkHand "123p 456m 789s NNN rr"))
                 @?= "Pair r, Closed chi: 456 Man, Closed chi: 123 Pin, Closed chi: 789 Sou, Closed pon: NNN"
         ]
 
