on master help sign in
tidying up
commitab9b72af8716424673ec416109281cf5dd5854f7 authorMark Wotton <mwotton@gmail.com> dateSat 6 Jun 2020, 10:24 (6 years ago) parentf5a8869
8 files changed+141−4
Makefile+2 package.yaml+2−1 roboservant.cabal+4−1 scripts/pre-commit.sh+12 src/Lib.hs−1 src/Roboservant.hs+71 stack.yaml+1−1 test/Spec.hs+49
Makefilenew file+2
@@ -0,0 +1,2 @@
1+testwatch:
2+ ghcid -c 'stack repl --test --ghc-options=-fobject-code' --allow-eval --restart="stack.yaml" --restart="package.yaml"
package.yaml+2−1
@@ -24,7 +24,8 @@ dependencies:
2424- servant
2525# - servant-server
2626- servant-flatten
27−
27+# test deps
28+- hspec
2829library:
2930 source-dirs: src
3031
roboservant.cabal+4−1
@@ -4,7 +4,7 @@ cabal-version: 1.12
44--
55-- see: https://github.com/sol/hpack
66--
7−-- hash: 33a62383bf0beb0aeb574784168345597afa6e00cb42cc943f6708e06370ae37
7+-- hash: 610f174fd4598a8ab9987ef588849ffd10eebdd86741c98dbe9219a1c979785e
88
99name: roboservant
1010version: 0.1.0.0
@@ -28,12 +28,14 @@ source-repository head
2828library
2929 exposed-modules:
3030 Lib
31+ Roboservant
3132 other-modules:
3233 Paths_roboservant
3334 hs-source-dirs:
3435 src
3536 build-depends:
3637 base >=4.7 && <5
38+ , hspec
3739 , servant
3840 , servant-flatten
3941 default-language: Haskell2010
@@ -48,6 +50,7 @@ test-suite roboservant-test
4850 ghc-options: -threaded -rtsopts -with-rtsopts=-N
4951 build-depends:
5052 base >=4.7 && <5
53+ , hspec
5154 , roboservant
5255 , servant
5356 , servant-flatten
scripts/pre-commit.shnew file+12
@@ -0,0 +1,12 @@
1+#!/bin/env bash
2+#
3+# Remember to link me to .git/hooks/pre-commit
4+
5+set -euo pipefail
6+
7+files=$((git diff --cached --name-only --diff-filter=ACMR | grep -Ei "\.hs$") || true)
8+if [ ! -z "${files}" ]; then
9+ echo "$files"
10+ echo "$files" | xargs ormolu --mode inplace
11+ git add $(echo "$files" | paste -s -d " " -)
12+fi
src/Lib.hs−1
@@ -103,4 +103,3 @@ main = pure ()
103103-- 'Baz -> whole value
104104-- '(Key Bar) -> key2
105105-- '(Key Foo) -> key1
106−
src/Roboservant.hsnew file+71
@@ -0,0 +1,71 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE KindSignatures #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE PolyKinds #-}
9+{-# LANGUAGE QuantifiedConstraints #-}
10+{-# LANGUAGE RankNTypes #-}
11+{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE TypeApplications #-}
13+{-# LANGUAGE TypeFamilies #-}
14+{-# LANGUAGE TypeOperators #-}
15+{-# LANGUAGE UndecidableInstances #-}
16+
17+module Roboservant where
18+
19+import Control.Applicative
20+import GHC.TypeLits
21+import Servant.API
22+
23+type family ExtractRespType (path :: *) :: * where
24+ ExtractRespType (_ :> b) = ExtractRespType b
25+ ExtractRespType (Verb (method :: StdMethod) (responseCode :: Nat) (contentTypes :: [*]) (respType :: *)) = respType
26+
27+type family ExtractRespTypes (paths :: *) :: [*] where
28+ ExtractRespTypes (a :<|> b) = ExtractRespTypes a <> ExtractRespTypes b
29+ ExtractRespTypes a = '[ExtractRespType a]
30+
31+type family (<>) (xs :: [k]) (ys :: [k]) :: [k] where
32+ (x ': xs) <> ys = x ': (xs <> ys)
33+ '[] <> ys = ys
34+
35+data List :: (* -> *) -> [*] -> * where
36+ Cons :: f a -> List f as -> List f (a ': as)
37+ Nil :: List f '[]
38+
39+class Insert f a as where
40+ insert :: a -> List f as -> List f as
41+
42+class Lookup f a as where
43+ lookup :: List f as -> f a
44+
45+instance Show (List f '[]) where
46+ show Nil = "Nil"
47+
48+instance (Show (List f as), forall a. Show a => Show (f a), Show a) => Show (List f (a ': as)) where
49+ show (Cons fa fas) = "(Cons " <> show fa <> " " <> show fas <> ")"
50+
51+storeOfApi :: forall api xs. (ExtractRespTypes api ~ xs, BuildStore [] xs) => List [] (ExtractRespTypes api)
52+storeOfApi = buildStore
53+
54+class BuildStore f (xs :: [*]) where
55+ buildStore :: List f xs
56+
57+instance BuildStore f '[] where
58+ buildStore = Nil
59+
60+instance (BuildStore f xs, Alternative f) => BuildStore f (x ': xs) where
61+ buildStore = Cons empty (buildStore @_ @xs)
62+-- 1.
63+-- Instead of just the resptype, let's return a tuple of (resptype, '[]::[ ? respType])
64+
65+-- 2.
66+-- break down respType into "useful" components
67+-- data Baz = Baz { key1 :: Key Foo, key2 :: Key Bar }
68+-- should insert into type-indexed list three elements
69+-- 'Baz -> whole value
70+-- '(Key Bar) -> key2
71+-- '(Key Foo) -> key1
stack.yaml+1−1
@@ -17,7 +17,7 @@
1717#
1818# resolver: ./custom-snapshot.yaml
1919# resolver: https://example.com/snapshots/2018-01-01.yaml
20−resolver: lts-15.6
20+resolver: lts-15.15
2121
2222# User packages to be built.
2323# Various formats can be used as shown in the example below.
test/Spec.hs+49
@@ -1,2 +1,51 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE KindSignatures #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE PolyKinds #-}
9+{-# LANGUAGE QuantifiedConstraints #-}
10+{-# LANGUAGE RankNTypes #-}
11+{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE TypeApplications #-}
13+{-# LANGUAGE TypeFamilies #-}
14+{-# LANGUAGE TypeOperators #-}
15+{-# LANGUAGE UndecidableInstances #-}
16+
17+import Roboservant
18+import Servant.API
19+import Test.Hspec
20+
21+newtype Foo = Foo Int
22+ deriving (Show)
23+
24+newtype Bar = Bar String
25+ deriving (Show)
26+
27+type FooApi = "foo" :> "fle" :> "far" :> Get '[JSON] Foo
28+
29+type BarApi = "bar" :> ReqBody '[JSON] Foo :> Post '[JSON] Bar
30+
31+type Api =
32+ FooApi :<|> BarApi
33+
34+type Foo' = ExtractRespType FooApi
35+
36+test :: ()
37+test = foo'EqualFoo
38+ where
39+ foo'EqualFoo :: Foo' ~ Foo => ()
40+ foo'EqualFoo = ()
41+
42+test' :: ()
43+test' = blah
44+ where
45+ blah :: ExtractRespTypes Api ~ '[Foo, Bar] => ()
46+ blah = ()
47+
48+storeOfOurApi = storeOfApi @Api
49+
150main :: IO ()
251main = putStrLn "Test suite not yet implemented"