diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,13 @@
+# Revision history for matrix-as-xyz
+
+## 0.1.1.0  -- 2018-06-05
+
+* CabalからStackに変更
+* API変更
+* 挙動の変更
+* Documentの整備
+* その他色々
+
+## 0.1.0.0  -- 2017-03-11
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2017, narumij
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of narumij nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# matrix-as-xyz
+
+Haskell General equivalent positions Library
+
+Treat matrix as xyz representation like International Tables for X-ray Crystallography
+
+## License
+
+See the [LICENSE](https://github.com/narumij/matrix-as-xyz/LICENSE)
+file in the repository.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/matrix-as-xyz.cabal b/matrix-as-xyz.cabal
new file mode 100644
--- /dev/null
+++ b/matrix-as-xyz.cabal
@@ -0,0 +1,85 @@
+-- This file has been generated from package.yaml by hpack version 0.28.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 19899810c3d6696ddbcceefa6fcb228661c87238cefcfc1bcdde512fba3dd8ba
+
+name:           matrix-as-xyz
+version:        0.1.1.0
+synopsis:       Read and Display representation of matrix like "x,y,z"
+description:    Please see the README on GitHub at <https://github.com/narumij/matrix-as-xyz#readme>
+category:       Chemistry
+homepage:       https://github.com/narumij/matrix-as-xyz#readme
+bug-reports:    https://github.com/narumij/matrix-as-xyz/issues
+author:         Jun Narumi
+maintainer:     narumij@gmail.com
+copyright:      Jun Narumi
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/narumij/matrix-as-xyz
+
+library
+  exposed-modules:
+      Data.Matrix.AsXYZ
+      Data.Matrix.AsXYZ.Parse
+      Data.Ratio.ParseFloat
+      Data.Ratio.Slash
+  other-modules:
+      Paths_matrix_as_xyz
+  hs-source-dirs:
+      src
+  build-depends:
+      QuickCheck
+    , base >=4.7 && <5
+    , hspec
+    , matrix
+    , parsec
+  default-language: Haskell2010
+
+test-suite matrix-as-xyz-doctest
+  type: exitcode-stdio-1.0
+  main-is: doctests.hs
+  other-modules:
+      AsXYZSpec
+      SlashSpec
+      Spec
+      Paths_matrix_as_xyz
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      QuickCheck
+    , base >=4.7 && <5
+    , doctest
+    , hspec
+    , matrix
+    , matrix-as-xyz
+    , parsec
+  default-language: Haskell2010
+
+test-suite matrix-as-xyz-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      AsXYZSpec
+      SlashSpec
+      Paths_matrix_as_xyz
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      QuickCheck
+    , base >=4.7 && <5
+    , hspec
+    , matrix
+    , matrix-as-xyz
+    , parsec
+  default-language: Haskell2010
diff --git a/src/Data/Matrix/AsXYZ.hs b/src/Data/Matrix/AsXYZ.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Matrix/AsXYZ.hs
@@ -0,0 +1,161 @@
+{- |
+Module      : Data.Matrix.AsXYZ
+Copyright   : (c) Jun Narumi 2017-2018
+License     : BSD3
+Maintainer  : narumij@gmail.com
+Stability   : experimental
+Portability : ?
+
+Read and Display matrix with xyz reperesentation. (like general equivalnet position of International tables of Crystallography.)
+
+-}
+module Data.Matrix.AsXYZ (
+  fromXYZ,
+  fromXYZ',
+  fromABC,
+  prettyXYZ,
+  prettyABC,
+  ) where
+
+import Control.Monad (join)
+import Data.Char (isAlpha)
+import Data.List (intercalate)
+import Data.Ratio (Ratio)
+import Data.Matrix (Matrix,fromList,fromLists,toLists,identity,zero,(<->))
+import Text.ParserCombinators.Parsec (parse,ParseError)
+
+import Data.Ratio.Slash (getRatio,Slash(..))
+import Data.Matrix.AsXYZ.Parse (equivalentPositions,transformPpABC,ratio)
+
+-- | Create a matirx from xyz coordinate string of general equivalent position
+--
+-- >                                      ( 1 % 1 0 % 1 0 % 1 0 % 1 )
+-- >                                      ( 0 % 1 1 % 1 0 % 1 0 % 1 )
+-- >                                      ( 0 % 1 0 % 1 1 % 1 0 % 1 )
+-- > fromXYZ "x,y,z" :: Matrix Rational = ( 0 % 1 0 % 1 0 % 1 1 % 1 )
+-- >
+-- >                                                  ( 1 % 1 0 % 1 0 % 1 1 % 2 )
+-- >                                                  ( 0 % 1 1 % 1 0 % 1 1 % 3 )
+-- >                                                  ( 0 % 1 0 % 1 1 % 1 1 % 4 )
+-- > fromXYZ "x+1/2,y+1/3,z+1/4" :: Matrix Rational = ( 0 % 1 0 % 1 0 % 1 1 % 1 )
+-- >
+-- >                                                              (  1  2  3  4 )
+-- >                                                              (  5  6  7  8 )
+-- >                                                              (  9 10 11 12 )
+-- > fromXYZ "x+2y+3z+4,5x+6y+7z+8,9x+10y+11z+12" :: Matrix Int = (  0  0  0  1 )
+fromXYZ :: Integral a => String -> Matrix (Ratio a)
+fromXYZ input = unsafeGet $ makeMatrix <$> parse (equivalentPositions ratio) input input
+
+-- | Maybe version
+fromXYZ' :: Integral a => String -> Maybe (Matrix (Ratio a))
+fromXYZ' input = get $ makeMatrix <$> parse (equivalentPositions ratio) input input
+
+-- | It's uses abc instead of xyz
+--
+-- >                                      ( 1 % 1 0 % 1 0 % 1 0 % 1 )
+-- >                                      ( 0 % 1 1 % 1 0 % 1 0 % 1 )
+-- >                                      ( 0 % 1 0 % 1 1 % 1 0 % 1 )
+-- > fromXYZ "a,b,c" :: Matrix Rational = ( 0 % 1 0 % 1 0 % 1 1 % 1 )
+fromABC :: Integral a => String -> Matrix (Ratio a)
+fromABC input = unsafeGet $ makeMatrix <$> parse (transformPpABC ratio) input input
+
+makeMatrix :: Num a => [[a]] -> Matrix a
+makeMatrix m = fromLists m <-> fromLists [[0,0,0,1]]
+
+unsafeGet :: Either ParseError a -> a
+unsafeGet e = case e of
+  Left s -> error $ show s
+  Right m -> m
+
+get :: Either ParseError a -> Maybe a
+get e = case e of
+  Left s -> Nothing
+  Right m -> Just m
+
+----------------------------------
+
+-- +または-が銭湯に必ずあるようにする
+addPlusSign :: String -> String
+addPlusSign xs@('-':_) = xs
+addPlusSign xs         = '+' : xs
+
+-- 符号付きの数値文字列にする
+numStr :: (Integral a) => Ratio a -> String
+numStr = addPlusSign . show . Slash
+
+varString :: (Integral a) => Ratio a -> String -> String
+varString num label
+　-- 0の場合省略
+  | num == 0   = ""
+  -- 4番目の項目で、変数が付かない場合、数値文字列化
+  | null label = numStr num
+  -- 数値が1で変数がある場合、数値を省略
+  | num == 1   = "+" ++ label
+  -- 数値が-1で変数がある場合、数値を省略
+  | num == -1  = "-" ++ label
+  -- それ以外では数値と変数を文字列化
+  | otherwise  = numStr num ++ label
+
+-- 正の係数がついた変数である
+isPrimary :: String -> Bool
+isPrimary x = (hasLetter . reverse) x && isPositive x
+
+hasLetter :: String -> Bool
+hasLetter (x:_) = isAlpha x
+hasLetter _     = False
+
+isPositive :: String -> Bool
+isPositive ('+':_) = True
+isPositive _       = False
+
+-- 正の係数がついた変数を先頭にする
+varSort :: [String] -> [String]
+varSort parts = filter isPrimary parts ++ filter (not . isPrimary) parts
+
+row :: (Integral a) => [String] -> [Ratio a] -> String
+row labels line = join . varSort $ zipWith varString line labels
+
+refineRow :: String -> String
+refineRow s
+  -- 全ての項目が省略されていると空文字列になっているので、0
+  | null s = "0"
+  -- 先頭の項目が正の場合、+記号を省略できるので削る
+  | head s == '+' = tail s
+  | otherwise = s
+
+rowString :: (Integral a) => [String] -> [Ratio a] -> String
+rowString labels line = refineRow (row labels line)
+
+xyzLabel :: [String]
+xyzLabel = ["x","y","z",""]
+
+abcLabel :: [String]
+abcLabel = ["a","b","c",""]
+
+showAs :: (Integral a) => [String] -> Matrix (Ratio a) -> String
+showAs labels = intercalate "," . map (rowString labels) . take 3 . toLists
+
+
+-- | Get the xyz representation of matrix
+--
+-- >>> prettyXYZ (identity 4 :: Matrix Rational)
+-- "x,y,z"
+--
+-- >           ( 0 % 1 0 % 1 0 % 1 1 % 2 )
+-- >           ( 0 % 1 0 % 1 0 % 1 2 % 3 )
+-- >           ( 0 % 1 0 % 1 0 % 1 4 % 5 )
+-- > prettyXYZ ( 0 % 1 0 % 1 0 % 1 1 % 1 ) = "1/2,2/3,4/5"
+prettyXYZ :: (Integral a) =>
+             Matrix (Ratio a) -- ^ 3x3, 3x4 or 4x4 matrix
+          -> String
+prettyXYZ = showAs xyzLabel
+
+
+-- | It's uses abc instead of xyz
+--
+-- >>> prettyABC (identity 4 :: Matrix Rational)
+-- "a,b,c"
+prettyABC :: (Integral a) =>
+             Matrix (Ratio a) -- ^ 3x3, 3x4 or 4x4 matrix
+          -> String
+prettyABC = showAs abcLabel
diff --git a/src/Data/Matrix/AsXYZ/Parse.hs b/src/Data/Matrix/AsXYZ/Parse.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Matrix/AsXYZ/Parse.hs
@@ -0,0 +1,225 @@
+{- |
+Module      : Data.Matrix.AsXYZ.Parse
+Copyright   : (c) Jun Narumi 2018
+License     : BSD3
+Maintainer  : narumij@gmail.com
+Stability   : experimental
+Portability : ?
+-}
+module Data.Matrix.AsXYZ.Parse (
+  Value,
+  equivalentPositions,
+  transformPpABC,
+  transformQqXYZ,
+  ratio,
+  integral,
+  floating,
+  ) where
+
+import Control.Monad
+import Data.Maybe
+import Data.List
+import Text.ParserCombinators.Parsec
+
+import Data.Ratio
+import Data.Ratio.Slash
+
+import Data.Ratio.ParseFloat (readFloatingPoint)
+
+import Data.Matrix (fromList,fromLists,Matrix(..),joinBlocks,(<->))
+
+-- | General equivalent positions parser
+equivalentPositions :: Num a =>
+　　　　　　　　　　　　　　ReadNum a -- ^ use converter below
+　　　　　　　　　　　　 -> CharParser () [[a]]
+equivalentPositions = components xyz
+
+-- | Same as equivalentPositions but uses abc instead of xyz
+transformPpABC :: Num a => ReadNum a -> CharParser () [[a]]
+transformPpABC = components abc
+
+-- | Alias of equivalentPositions
+transformQqXYZ :: Num a => ReadNum a -> CharParser () [[a]]
+transformQqXYZ = components xyz
+
+-- | Converter of 3 kind of number (int,float,ratio) string to rational
+--
+-- Use it for equivalentPositions or something parseer
+ratio :: Integral a => Value -> Either String (Ratio a)
+ratio (I s) = Right $ getRatio . read $ s
+ratio (R s) = Right $ getRatio . read $ s
+ratio (F s) = Right $ readFloatingPoint s
+
+-- | Converter of integral number description to integral
+--
+-- Use it for equivalentPositions or something parseer
+integral :: Integral a => Value -> Either String a
+integral (I s) = Right $ fromIntegral (read s :: Integer)
+integral (R s) = Left  $ "cannot convert to integer from " ++ s ++ "."
+integral (F s) = Left  $ "cannot convert to integer from " ++ s ++ "."
+
+-- | Converter of 3 kind of number description to floating point
+--
+-- Use it for equivalentPositions or something parseer
+floating :: Floating a => Value -> Either String a
+floating v = fromRational <$> ratio v
+
+-- 数値の型情報
+data Val a
+  -- 整数
+  = I a
+  -- 浮動小数
+  | F a
+  -- 分数
+  | R a
+  deriving Show
+
+instance Functor Val where
+  fmap f (I a) = I (f a)
+  fmap f (F a) = F (f a)
+  fmap f (R a) = R (f a)
+
+-- | Type of numeric type information generated in the middle
+type Value = Val String
+
+data Var a
+  = X a
+  | Y a
+  | Z a
+  | W a
+  deriving (Show,Eq)
+
+instance Functor Var where
+  fmap f (X a) = X (f a)
+  fmap f (Y a) = Y (f a)
+  fmap f (Z a) = Z (f a)
+  fmap f (W a) = W (f a)
+
+v (Just 'x') = X
+v (Just 'a') = X
+v (Just 'y') = Y
+v (Just 'b') = Y
+v (Just 'z') = Z
+v (Just 'c') = Z
+v Nothing = W
+
+sign :: CharParser () Char
+sign = oneOf "-+"
+
+zero :: CharParser () String
+zero = do
+  char '0'
+  return "0"
+
+num :: CharParser () String
+num = do
+  x <- oneOf "123456789"
+  xs <- many digit
+  return $ x : xs
+
+int :: CharParser () String
+int = zero <|> num
+
+integer :: CharParser () Value
+integer = do
+  i <- int
+  return (I i)
+
+float :: CharParser () Value
+float = do
+  i <- option "" int
+  char '.'
+  f <- many digit
+  return (F $ i ++ "." ++ f )
+
+fract :: CharParser () Value
+fract = do
+  n <- many1 digit
+  option () spaces
+  char '/'
+  option () spaces
+  d <- many1 digit
+  return (R $ n ++ "/" ++ d)
+
+number' :: CharParser () Value
+number'
+  =   try fract
+  <|> try float
+  <|> integer
+
+-- | numRead関数のシグネチャの簡易表記
+type ReadNum b = Value -> Either String b
+
+number :: ReadNum b -> CharParser () b
+number numRead = do
+  n <- number'
+  case numRead n of
+    Left s -> fail s
+    Right nn -> return nn
+
+elementBody :: CharParser () Char -> ReadNum a -> CharParser () (Maybe a, Maybe Char)
+elementBody var conv = do
+  n <- optionMaybe (number conv)
+  option () spaces
+  v <- optionMaybe var
+  option () spaces
+  guard (isJust n || isJust v)
+  return (n,v)
+
+minus :: Num a => Maybe Char -> (a -> a)
+minus (Just '-') = negate
+minus (Just '+') = id
+minus Nothing    = id
+
+one :: Num a => CharParser () Char -> ReadNum a -> CharParser () (Var a)
+one var numRead = do
+  s <- optionMaybe sign
+  option () spaces
+  (n,l) <- elementBody var numRead
+  return $ v l . minus s . fromMaybe 1 $ n
+
+other :: Num a => CharParser () Char -> ReadNum a -> CharParser () (Var a)
+other var numRead = do
+  s <- sign
+  option () spaces
+  (n,l) <- elementBody var numRead
+  return $ v l . minus (Just s) . fromMaybe 1 $ n
+
+overlap :: Eq a => [a] -> Bool
+overlap n = (length . nub) n /= length n
+
+constructRow :: Num a => [Var a] -> [a]
+constructRow = map (fromMaybe 0 . listToMaybe . catMaybes) . transpose . map toArray
+  where
+    toArray (X n) = [Just n,Nothing,Nothing,Nothing]
+    toArray (Y n) = [Nothing,Just n,Nothing,Nothing]
+    toArray (Z n) = [Nothing,Nothing,Just n,Nothing]
+    toArray (W n) = [Nothing,Nothing,Nothing,Just n]
+
+component :: Num b => CharParser () Char -> ReadNum b -> CharParser () [b]
+component var numRead = do
+  option () spaces
+  x <- one var numRead
+  xs <- many (other var numRead)
+  option () spaces
+  let mm = x : xs
+  if overlap (map void mm)
+    then
+      fail "overlaps var type"
+    else
+      return (constructRow mm)
+
+components :: Num a => CharParser () Char -> ReadNum a -> CharParser () [[a]]
+components var conv = do
+  a <- component var conv
+  char ','
+  b <- component var conv
+  char ','
+  c <- component var conv
+  return [a,b,c]
+
+xyz :: CharParser () Char
+xyz = oneOf "xyzXYZ"
+
+abc :: CharParser () Char
+abc = oneOf "abcABC"
diff --git a/src/Data/Ratio/ParseFloat.hs b/src/Data/Ratio/ParseFloat.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Ratio/ParseFloat.hs
@@ -0,0 +1,117 @@
+{- |
+Module      : Data.Ratio.ParseFloat
+Copyright   : (c) Jun Narumi 2018
+License     : BSD3
+Maintainer  : narumij@gmail.com
+Stability   : experimental
+Portability : ?
+
+Floating point parser
+
+Temporary solution to the problem below
+
+> ghci> realToFrac (read "1.1" :: Double) :: Rational
+> 2476979795053773 % 2251799813685248
+
+-}
+module Data.Ratio.ParseFloat (
+  readFloatingPoint,
+  floating,
+  ) where
+
+import Data.Ratio
+import Text.ParserCombinators.Parsec
+
+-- このような一見、車輪の再発明に思えるコードをわざわざ書いたのは
+-- ghci> realToFrac (read "1.1" :: Double) :: Rational
+-- 2476979795053773 % 2251799813685248
+-- という問題に対処するため。
+-- これ以外に良い方法、良い書き方が分かれば、削除します。
+
+-- | Obtain fractions from floating point representation string
+--
+-- >>> readFloatingPoint "1.1"
+-- 11 % 10
+-- >>> readFloatingPoint "0.5"
+-- 1 % 2
+-- >>> readFloatingPoint ".5"
+-- 1 % 2
+-- >>> readFloatingPoint "10."
+-- 10 % 1
+-- >>> readFloatingPoint "10"
+-- 10 % 1
+-- >>> readFloatingPoint "10.2"
+-- 51 % 5
+-- >>> readFloatingPoint "1e-1"
+-- 1 % 10
+-- >>> readFloatingPoint "-0.5e-1"
+-- (-1) % 20
+-- >>> readFloatingPoint "5e2"
+-- 500 % 1
+-- >>> readFloatingPoint "5e+2"
+-- 500 % 1
+readFloatingPoint :: Integral a => String -> Ratio a
+readFloatingPoint s = case parse floating s s of
+  Left  e -> error $ show e
+  Right r -> r
+
+zero :: CharParser () String
+zero = do
+  char '0'
+  return "0"
+
+num :: CharParser () String
+num = do
+  x <- oneOf "123456789"
+  xs <- many digit
+  return $ x : xs
+
+int :: CharParser () String
+int = zero <|> num
+
+sign :: CharParser () Char
+sign = oneOf "-+"
+
+decimal :: CharParser () String
+decimal = do
+  char '.'
+  many digit
+
+exponent' :: Integral a => CharParser () a
+exponent' = do
+  oneOf "eE"
+  s <- optionMaybe sign
+  e <- int
+  return $ signPart s $ read' e
+
+-- | Parser section
+floating :: Integral a => CharParser () (Ratio a)
+floating = do
+  s <- optionMaybe sign
+  i <- option "" int
+  f <- option "" decimal
+  e <- optionMaybe exponent'
+  return $ signPart s . expPart e $ intPart i + decimalPart f
+
+signPart :: Num a => Maybe Char -> a -> a
+signPart (Just '-') = negate
+signPart _          = id
+
+intPart :: Integral a => String -> Ratio a
+intPart "" = 0
+intPart i  = read' i % 1
+
+decimalPart :: Integral a => String -> Ratio a
+decimalPart "" = 0
+decimalPart f  | read f == 0 = 0
+               | otherwise = read' f % (10 ^ length f)
+
+-- 整数型のｒead instanceを隠蔽している
+read' :: Integral a => String -> a
+read' s = fromIntegral (read s :: Integer)
+
+expPart :: Integral a => Maybe Integer -> Ratio a -> Ratio a
+expPart Nothing      = id
+expPart (Just s)     | s == 0    = id
+                     | s < 0     = flip (/) (10 ^ abs s)
+                     | otherwise = flip (*) (10 ^ s)
diff --git a/src/Data/Ratio/Slash.hs b/src/Data/Ratio/Slash.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Ratio/Slash.hs
@@ -0,0 +1,67 @@
+{- |
+Module      : Data.Ratio.Slash
+Copyright   : (c) Jun Narumi 2018
+License     : BSD3
+Maintainer  : narumij@gmail.com
+Stability   : experimental
+Portability : ?
+
+Handle fractions described in /, not%
+
+-}
+
+module Data.Ratio.Slash (
+  Slash(..),
+  ) where
+
+import Control.Monad (guard)
+import Control.Applicative ((<|>))
+import Data.Ratio
+import Numeric
+
+-- | Type of read and show slash form rational
+--
+-- >>> getRatio . read $ "1/2"
+-- 1 % 2
+--
+-- >>> map getRatio . read $ "[1/2,3/4,5/6]"
+-- [1 % 2,3 % 4,5 % 6]
+--
+-- >>> Slash (1 % 2)
+-- 1/2
+--
+-- >>> map Slash [1%2,3%4,5%6]
+-- [1/2,3/4,5/6]
+--
+newtype Slash a
+  = Slash {
+    getRatio :: Ratio a
+    } deriving (Eq,Ord)
+
+instance (Integral a) => Show (Slash a) where
+  showsPrec _ (Slash n)
+    | denominator n == 1
+      = showSigned showInt 0 (numerator n)
+    | otherwise
+      = showSigned showInt 0 (numerator n) . showString "/" . showInt (denominator n)
+
+instance (Integral a) => Read (Slash a) where
+  readsPrec _ n = do
+    ( ( n, d ), st ) <- slashOrInteger n
+    guard $ d /= 0
+    return ( Slash $ n % d , st )
+
+integer :: (Integral a) => ReadS (a,a)
+integer n = do
+  ( n, st ) <- readSigned readDec n
+  return ( ( n, 1 ), st )
+
+slash :: (Integral a) => ReadS (a,a)
+slash n = do
+  ( numer, st  )  <- readSigned readDec n
+  ( "/"  , st1 ) <- lex st
+  ( denom, st2 ) <- readDec st1
+  return ( ( numer, denom ), st2)
+
+slashOrInteger :: (Integral a) => ReadS (a,a)
+slashOrInteger n = take 1 $ slash n <|> integer n
diff --git a/test/AsXYZSpec.hs b/test/AsXYZSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/AsXYZSpec.hs
@@ -0,0 +1,54 @@
+module AsXYZSpec where
+
+import Control.Exception (evaluate)
+
+import Test.Hspec
+import Data.Ratio
+import Data.Matrix
+import Data.Matrix.AsXYZ
+
+spec :: Spec
+spec = do
+
+   describe "Data.Matrix.AsXYZ.fromXYZ" $ do
+
+     it "read empty throws exception" $ do
+       evaluate (fromXYZ "") `shouldThrow` anyException
+
+     it "read x,y,z" $ do
+       fromXYZ "x,y,z" `shouldBe` (identity 4)
+
+
+   describe "Data.Matrix.AsXYZ.prettyXYZ" $ do
+
+     it "show 0 (3x3)" $ do
+       prettyXYZ (zero 3 3) `shouldBe` "0,0,0"
+
+     it "show 0 (3x4)" $ do
+       prettyXYZ (zero 3 4) `shouldBe` "0,0,0"
+
+     it "show 0 (4x4)" $ do
+       prettyXYZ (zero 4 4) `shouldBe` "0,0,0"
+
+     it "show 1 (4x4)" $ do
+       prettyXYZ (identity 4) `shouldBe` "x,y,z"
+
+     it "show 1 (3x4)" $ do
+       prettyXYZ (submatrix 1 3 1 4 $ identity 4) `shouldBe` "x,y,z"
+
+     it "show 1 (3x3)" $ do
+       prettyXYZ (submatrix 1 3 1 3 $ identity 4) `shouldBe` "x,y,z"
+
+     it "positive first" $ do
+       prettyXYZ (fromLists [[1,-1,-1],[-1,1,-1],[-1,-1,1]]) `shouldBe` "x-y-z,y-x-z,z-x-y"
+
+     it "number last" $ do
+       prettyXYZ (fromLists [[-1,-1,-1,-1],[-1,-1,-1,0],[-1,-1,-1,1]]) `shouldBe` "-x-y-z-1,-x-y-z,-x-y-z+1"
+
+   describe "Data.Matrix.AsXYZ.prettyABC" $ do
+
+     it "show 0" $ do
+       prettyABC (zero 4 4) `shouldBe` "0,0,0"
+
+     it "show 1" $ do
+       prettyABC (identity 4) `shouldBe` "a,b,c"
diff --git a/test/SlashSpec.hs b/test/SlashSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/SlashSpec.hs
@@ -0,0 +1,30 @@
+module SlashSpec where
+
+import Test.Hspec
+import Test.Hspec.QuickCheck
+import Test.QuickCheck hiding ((.&.))
+
+import Control.Monad
+import Data.Ratio
+import Data.Ratio.Slash
+
+spec :: Spec
+spec = do
+  describe "rational" $ do
+
+    prop "read" $
+      \n d -> d /= 0 && n /= 0 && d > 1 && denominator ( n % d ) > 1 ==>
+        ( (read $ join [show n,"/",show d] ) :: Slash Integer ) `shouldBe` ( Slash $ n % d )
+
+    prop "both ways" $
+      \n d -> d /= 0 && n /= 0 && d > 1 && denominator ( n % d ) > 1 ==>
+        ( read . show $ Slash ( n % d ) :: Slash Integer ) `shouldBe` ( Slash $ n % d )
+
+  describe "integer" $ do
+    prop "read" $
+      \n -> True ==>
+        ( (read $ show n ) :: Slash Integer ) `shouldBe` ( Slash $ n % 1 )
+
+    prop "both ways" $
+      \n -> True ==>
+        ( read . show $ Slash ( n % 1 ) :: Slash Integer ) `shouldBe` ( Slash $ n % 1 )
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/test/doctests.hs b/test/doctests.hs
new file mode 100644
--- /dev/null
+++ b/test/doctests.hs
@@ -0,0 +1,7 @@
+import Test.DocTest
+
+main = doctest [
+  "src/Data/Ratio/Slash.hs",
+  "src/Data/Ratio/ParseFloat.hs",
+  "src/Data/Matrix/AsXYZ.hs"
+  ]
