From: Evgenii Akentev Date: Thu, 7 Jan 2021 15:49:51 +0000 (+0500) Subject: Add README and more examples. X-Git-Url: https://git.ak3n.com/?a=commitdiff_plain;h=095b1d1ee4a3037c95b5191254d97b49a3a054ae;p=handle-examples.git Add README and more examples. --- diff --git a/.gitignore b/.gitignore index 4c9e245..bbdbf82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store dist dist-* cabal-dev diff --git a/README.md b/README.md index 8b12c7c..d77edfb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ -# backpack-handle-example +This repository contains examples of the Handle pattern. We start from `simple` that contains domain logic and iterate trying to use records and backpack as a way to test the domain logic. -The examples of the Handle pattern in simple case, with records, and backpack. +- `simple` is a library with two modules: `WeatherProvider` (provides data) and `WeatherReporter` (uses the data to create a report). + +- `simple-handle` introduces a single-implementation Handle to both modules. + +- `records-handle` implements a polymorphic Handle for `WeatherProvider` allowing us to replace the implementation and write tests for domain logic. + +- `backpack-handle` does the same thing as `records-handle` but using Backpack instead. It allows us to specialize function calls. + +- `backpack-handles` goes further and makes both `WeatherProvider` and `WeatherReporter` signatures. Unfortunately, it doesn't work yet. diff --git a/backpack-handle/CHANGELOG.md b/backpack-handle/CHANGELOG.md deleted file mode 100644 index 806c22c..0000000 --- a/backpack-handle/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Revision history for backpack-handle-pattern - -## 0.1.0.0 -- YYYY-mm-dd - -* First version. Released on an unsuspecting world. diff --git a/backpack-handle/Main.hs b/backpack-handle/Main.hs index 07cd3de..197df48 100644 --- a/backpack-handle/Main.hs +++ b/backpack-handle/Main.hs @@ -9,5 +9,6 @@ import qualified WeatherReporter main :: IO () main = do let wph = SuperWeatherProvider.new - weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wph + let wrh = WeatherReporter.new wph + weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wrh putStrLn weatherReportInLondon diff --git a/backpack-handle/backpack-handle.cabal b/backpack-handle/backpack-handle.cabal index c427729..3bf756b 100644 --- a/backpack-handle/backpack-handle.cabal +++ b/backpack-handle/backpack-handle.cabal @@ -28,7 +28,7 @@ library test-impl default-language: Haskell2010 build-depends: base -executable backpack-handle-exe +executable main main-is: Main.hs build-depends: base >=4.13 && <4.14 , impl diff --git a/backpack-handle/domain/WeatherReporter.hs b/backpack-handle/domain/WeatherReporter.hs index e096750..8a521e9 100644 --- a/backpack-handle/domain/WeatherReporter.hs +++ b/backpack-handle/domain/WeatherReporter.hs @@ -1,11 +1,23 @@ module WeatherReporter where -import WeatherProvider +import qualified WeatherProvider type WeatherReport = String --- | This is domain logic. It uses `WeatherProvider` to get the actual data. -getCurrentWeatherReportInLondon :: WeatherProvider.Handle -> IO WeatherReport -getCurrentWeatherReportInLondon wph = do +-- | We hide dependencies in the handle +data Handle = Handle { weatherProvider :: WeatherProvider.Handle } + +-- | Constructor for Handle +new :: WeatherProvider.Handle -> Handle +new = Handle + +-- | Domain logic. Usually some pure code that might use mtl, free monads, etc. +createWeatherReport :: WeatherProvider.WeatherData -> WeatherReport +createWeatherReport (WeatherProvider.WeatherData temp) = + "The current temperature in London is " ++ (show temp) + +-- | Domain logic that uses external dependency to get data and process it. +getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport +getCurrentWeatherReportInLondon (Handle wph) = do weatherData <- WeatherProvider.getWeatherData wph "London" "now" - return $ "Current temperature in London is " ++ (show $ temperature weatherData) \ No newline at end of file + return $ createWeatherReport weatherData diff --git a/backpack-handle/test/Test.hs b/backpack-handle/test/Test.hs index 18dd2e5..83d1e92 100644 --- a/backpack-handle/test/Test.hs +++ b/backpack-handle/test/Test.hs @@ -1,22 +1,23 @@ import Test.Hspec -import qualified TestWeatherProvider import qualified WeatherProvider import qualified WeatherReporter main :: IO () main = hspec spec -weatherWithTemp :: WeatherProvider.Temperature -> WeatherProvider.Handle -weatherWithTemp = TestWeatherProvider.new . TestWeatherProvider.Config +weatherWithTemp :: WeatherProvider.Temperature -> WeatherReporter.Handle +weatherWithTemp = WeatherReporter.new + . WeatherProvider.new + . WeatherProvider.Config spec :: Spec spec = describe "WeatherReporter" $ do it "weather in London is 0" $ do weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $ weatherWithTemp 0 - weatherReportInLondon `shouldBe` "Current temperature in London is 0" + weatherReportInLondon `shouldBe` "The current temperature in London is 0" it "weather in London is -5" $ do weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $ weatherWithTemp (-5) - weatherReportInLondon `shouldBe` "Current temperature in London is -5" + weatherReportInLondon `shouldBe` "The current temperature in London is -5" diff --git a/backpack-handles/LICENSE b/backpack-handles/LICENSE new file mode 100644 index 0000000..9eea539 --- /dev/null +++ b/backpack-handles/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Evgenii Akentev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/backpack-handles/Main.hs b/backpack-handles/Main.hs new file mode 100644 index 0000000..0e6baa0 --- /dev/null +++ b/backpack-handles/Main.hs @@ -0,0 +1,13 @@ +module Main where + +import qualified SuperWeatherProvider +import qualified SuperWeatherReporter + +-- | This is an actual application where we use +-- our concrete implementation of `WeatherProvider`. +main :: IO () +main = do + let wph = SuperWeatherProvider.new + let wpr = SuperWeatherReporter.Handle wph + weatherReportInLondon <- SuperWeatherReporter.getCurrentWeatherReportInLondon wpr + putStrLn weatherReportInLondon diff --git a/backpack-handles/Setup.hs b/backpack-handles/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/backpack-handles/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/backpack-handles/backpack-handles.cabal b/backpack-handles/backpack-handles.cabal new file mode 100644 index 0000000..e8ee369 --- /dev/null +++ b/backpack-handles/backpack-handles.cabal @@ -0,0 +1,57 @@ +cabal-version: >=2 +name: backpack-handles +version: 0.1.0.0 +license-file: LICENSE +author: Evgenii Akentev +maintainer: i@ak3n.com +build-type: Simple +extra-source-files: CHANGELOG.md + +library domain + hs-source-dirs: domain + signatures: WeatherProvider + default-language: Haskell2010 + build-depends: base + +library domain-reporter + hs-source-dirs: domain + signatures: WeatherReporter + default-language: Haskell2010 + build-depends: base, domain + +library impl + hs-source-dirs: impl + exposed-modules: SuperWeatherProvider + , SuperWeatherReporter + reexported-modules: SuperWeatherProvider as WeatherProvider, + SuperWeatherReporter as WeatherReporter + default-language: Haskell2010 + build-depends: base + +library test-impl + hs-source-dirs: test-impl + exposed-modules: TestWeatherProvider + reexported-modules: TestWeatherProvider as WeatherProvider + default-language: Haskell2010 + build-depends: base + +executable main + main-is: Main.hs + build-depends: base >=4.13 && <4.14 + , impl + , domain + default-language: Haskell2010 + +test-suite spec + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: Test.hs + default-language: Haskell2010 + build-depends: base >= 4.7 && < 5 + , QuickCheck + , hspec + , domain + , test-impl + , impl + mixins: + impl (WeatherProvider as UnusedWeatherProvider, WeatherReporter) diff --git a/backpack-handles/domain/WeatherProvider.hsig b/backpack-handles/domain/WeatherProvider.hsig new file mode 100644 index 0000000..56de95a --- /dev/null +++ b/backpack-handles/domain/WeatherProvider.hsig @@ -0,0 +1,14 @@ +signature WeatherProvider where + +data Temperature +instance Show Temperature + +data WeatherData = WeatherData { temperature :: Temperature } + +type Location = String +type Day = String + +data Handle + +-- | The interface of `WeatherProvider` with available methods. +getWeatherData :: Handle -> Location -> Day -> IO WeatherData diff --git a/backpack-handles/domain/WeatherReporter.hsig b/backpack-handles/domain/WeatherReporter.hsig new file mode 100644 index 0000000..17ea47b --- /dev/null +++ b/backpack-handles/domain/WeatherReporter.hsig @@ -0,0 +1,10 @@ +signature WeatherReporter where + +import qualified WeatherProvider + +type WeatherReport = String + +data Handle = Handle { weatherProvider :: WeatherProvider.Handle } + +-- | This is domain logic. It uses `WeatherProvider` to get the actual data. +getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport diff --git a/backpack-handles/impl/SuperWeatherProvider.hs b/backpack-handles/impl/SuperWeatherProvider.hs new file mode 100644 index 0000000..1a29069 --- /dev/null +++ b/backpack-handles/impl/SuperWeatherProvider.hs @@ -0,0 +1,16 @@ +module SuperWeatherProvider where + +type Temperature = Int +data WeatherData = WeatherData { temperature :: Temperature } + +type Location = String +type Day = String + +data Handle = Handle + +new :: Handle +new = Handle + +-- | This is some concrete implementation `WeatherProvider` interface +getWeatherData :: Handle -> Location -> Day -> IO WeatherData +getWeatherData _ _ _ = return $ WeatherData 30 diff --git a/backpack-handles/impl/SuperWeatherReporter.hs b/backpack-handles/impl/SuperWeatherReporter.hs new file mode 100644 index 0000000..4a6ed2b --- /dev/null +++ b/backpack-handles/impl/SuperWeatherReporter.hs @@ -0,0 +1,25 @@ +module SuperWeatherReporter where + +import qualified SuperWeatherProvider + +type WeatherReport = String + +type WeatherProviderHandle = SuperWeatherProvider.Handle + +-- | We hide dependencies in the handle +data Handle = Handle { weatherProvider :: SuperWeatherProvider.Handle } + +-- | Constructor for Handle +new :: SuperWeatherProvider.Handle -> Handle +new = Handle + +-- | Domain logic. Usually some pure code that might use mtl, free monads, etc. +createWeatherReport :: SuperWeatherProvider.WeatherData -> WeatherReport +createWeatherReport (SuperWeatherProvider.WeatherData temp) = + "The current temperature in London is " ++ (show temp) + +-- | Domain logic that uses external dependency to get data and process it. +getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport +getCurrentWeatherReportInLondon (Handle wph) = do + weatherData <- SuperWeatherProvider.getWeatherData wph "London" "now" + return $ createWeatherReport weatherData diff --git a/backpack-handles/test-impl/TestWeatherProvider.hs b/backpack-handles/test-impl/TestWeatherProvider.hs new file mode 100644 index 0000000..900b102 --- /dev/null +++ b/backpack-handles/test-impl/TestWeatherProvider.hs @@ -0,0 +1,23 @@ +module TestWeatherProvider where + +type Temperature = Int +data WeatherData = WeatherData { temperature :: Temperature } + +type Location = String +type Day = String + +-- | This is a configuration that allows to setup the provider for tests. +data Config = Config + { initTemperature :: Temperature + } + +data Handle = Handle + { config :: Config + } + +new :: Config -> Handle +new = Handle + +-- | This is an implementation `WeatherProvider` interface for tests +getWeatherData :: Handle -> Location -> Day -> IO WeatherData +getWeatherData (Handle conf) _ _ = return $ WeatherData $ initTemperature conf diff --git a/backpack-handles/test/Test.hs b/backpack-handles/test/Test.hs new file mode 100644 index 0000000..b329480 --- /dev/null +++ b/backpack-handles/test/Test.hs @@ -0,0 +1,23 @@ +import Test.Hspec + +import qualified WeatherProvider +import qualified WeatherReporter + +main :: IO () +main = hspec spec + +weatherWithTemp :: WeatherProvider.Temperature -> WeatherReporter.Handle +weatherWithTemp t = WeatherReporter.new + $ WeatherProvider.new + $ WeatherProvider.Config t + +spec :: Spec +spec = describe "WeatherReporter" $ do + it "weather in London is 0" $ do + weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $ + weatherWithTemp 0 + weatherReportInLondon `shouldBe` "The current temperature in London is 0" + it "weather in London is -5" $ do + weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $ + weatherWithTemp (-5) + weatherReportInLondon `shouldBe` "The current temperature in London is -5" diff --git a/records-handle/CHANGELOG.md b/records-handle/CHANGELOG.md deleted file mode 100644 index 806c22c..0000000 --- a/records-handle/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Revision history for backpack-handle-pattern - -## 0.1.0.0 -- YYYY-mm-dd - -* First version. Released on an unsuspecting world. diff --git a/records-handle/Main.hs b/records-handle/Main.hs index 07cd3de..197df48 100644 --- a/records-handle/Main.hs +++ b/records-handle/Main.hs @@ -9,5 +9,6 @@ import qualified WeatherReporter main :: IO () main = do let wph = SuperWeatherProvider.new - weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wph + let wrh = WeatherReporter.new wph + weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wrh putStrLn weatherReportInLondon diff --git a/records-handle/domain/WeatherReporter.hs b/records-handle/domain/WeatherReporter.hs index e096750..8a521e9 100644 --- a/records-handle/domain/WeatherReporter.hs +++ b/records-handle/domain/WeatherReporter.hs @@ -1,11 +1,23 @@ module WeatherReporter where -import WeatherProvider +import qualified WeatherProvider type WeatherReport = String --- | This is domain logic. It uses `WeatherProvider` to get the actual data. -getCurrentWeatherReportInLondon :: WeatherProvider.Handle -> IO WeatherReport -getCurrentWeatherReportInLondon wph = do +-- | We hide dependencies in the handle +data Handle = Handle { weatherProvider :: WeatherProvider.Handle } + +-- | Constructor for Handle +new :: WeatherProvider.Handle -> Handle +new = Handle + +-- | Domain logic. Usually some pure code that might use mtl, free monads, etc. +createWeatherReport :: WeatherProvider.WeatherData -> WeatherReport +createWeatherReport (WeatherProvider.WeatherData temp) = + "The current temperature in London is " ++ (show temp) + +-- | Domain logic that uses external dependency to get data and process it. +getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport +getCurrentWeatherReportInLondon (Handle wph) = do weatherData <- WeatherProvider.getWeatherData wph "London" "now" - return $ "Current temperature in London is " ++ (show $ temperature weatherData) \ No newline at end of file + return $ createWeatherReport weatherData diff --git a/records-handle/records-handle.cabal b/records-handle/records-handle.cabal index ac1318e..1540e7e 100644 --- a/records-handle/records-handle.cabal +++ b/records-handle/records-handle.cabal @@ -28,7 +28,7 @@ library test-impl build-depends: base , domain -executable records-handle-exe +executable main main-is: Main.hs build-depends: base >=4.13 && <4.14 , domain diff --git a/records-handle/test/Test.hs b/records-handle/test/Test.hs index 18dd2e5..7466dd4 100644 --- a/records-handle/test/Test.hs +++ b/records-handle/test/Test.hs @@ -7,16 +7,18 @@ import qualified WeatherReporter main :: IO () main = hspec spec -weatherWithTemp :: WeatherProvider.Temperature -> WeatherProvider.Handle -weatherWithTemp = TestWeatherProvider.new . TestWeatherProvider.Config +weatherWithTemp :: WeatherProvider.Temperature -> WeatherReporter.Handle +weatherWithTemp = WeatherReporter.new + . TestWeatherProvider.new + . TestWeatherProvider.Config spec :: Spec spec = describe "WeatherReporter" $ do it "weather in London is 0" $ do weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $ weatherWithTemp 0 - weatherReportInLondon `shouldBe` "Current temperature in London is 0" + weatherReportInLondon `shouldBe` "The current temperature in London is 0" it "weather in London is -5" $ do weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon $ weatherWithTemp (-5) - weatherReportInLondon `shouldBe` "Current temperature in London is -5" + weatherReportInLondon `shouldBe` "The current temperature in London is -5" diff --git a/simple-handle/CHANGELOG.md b/simple-handle/CHANGELOG.md deleted file mode 100644 index 806c22c..0000000 --- a/simple-handle/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Revision history for backpack-handle-pattern - -## 0.1.0.0 -- YYYY-mm-dd - -* First version. Released on an unsuspecting world. diff --git a/simple-handle/Main.hs b/simple-handle/Main.hs index e1d6702..c32c6e9 100644 --- a/simple-handle/Main.hs +++ b/simple-handle/Main.hs @@ -6,5 +6,6 @@ import qualified WeatherReporter main :: IO () main = do let wph = WeatherProvider.new - weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wph + let wrh = WeatherReporter.new wph + weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon wrh putStrLn weatherReportInLondon diff --git a/simple-handle/domain/WeatherReporter.hs b/simple-handle/domain/WeatherReporter.hs index 88a9d44..8a521e9 100644 --- a/simple-handle/domain/WeatherReporter.hs +++ b/simple-handle/domain/WeatherReporter.hs @@ -1,16 +1,23 @@ module WeatherReporter where -import WeatherProvider +import qualified WeatherProvider type WeatherReport = String +-- | We hide dependencies in the handle +data Handle = Handle { weatherProvider :: WeatherProvider.Handle } + +-- | Constructor for Handle +new :: WeatherProvider.Handle -> Handle +new = Handle + -- | Domain logic. Usually some pure code that might use mtl, free monads, etc. -createWeatherReport :: WeatherData -> WeatherReport -createWeatherReport (WeatherData temp) = +createWeatherReport :: WeatherProvider.WeatherData -> WeatherReport +createWeatherReport (WeatherProvider.WeatherData temp) = "The current temperature in London is " ++ (show temp) -- | Domain logic that uses external dependency to get data and process it. -getCurrentWeatherReportInLondon :: WeatherProvider.Handle -> IO WeatherReport -getCurrentWeatherReportInLondon wph = do +getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport +getCurrentWeatherReportInLondon (Handle wph) = do weatherData <- WeatherProvider.getWeatherData wph "London" "now" return $ createWeatherReport weatherData diff --git a/simple-handle/simple-handle.cabal b/simple-handle/simple-handle.cabal index 2a349a8..94b079b 100644 --- a/simple-handle/simple-handle.cabal +++ b/simple-handle/simple-handle.cabal @@ -14,7 +14,7 @@ library domain default-language: Haskell2010 build-depends: base -executable simple-handle-exe +executable main main-is: Main.hs build-depends: base >=4.13 && <4.14 , domain diff --git a/simple/LICENSE b/simple/LICENSE new file mode 100644 index 0000000..9eea539 --- /dev/null +++ b/simple/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Evgenii Akentev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/simple/Main.hs b/simple/Main.hs new file mode 100644 index 0000000..c0cbd2b --- /dev/null +++ b/simple/Main.hs @@ -0,0 +1,8 @@ +module Main where + +import qualified WeatherReporter + +main :: IO () +main = do + weatherReportInLondon <- WeatherReporter.getCurrentWeatherReportInLondon + putStrLn weatherReportInLondon diff --git a/simple/Setup.hs b/simple/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/simple/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/simple/domain/WeatherProvider.hs b/simple/domain/WeatherProvider.hs new file mode 100644 index 0000000..4cb6f5c --- /dev/null +++ b/simple/domain/WeatherProvider.hs @@ -0,0 +1,12 @@ +module WeatherProvider where + +type Temperature = Int +data WeatherData = WeatherData { temperature :: Temperature } + +type Location = String +type Day = String + +-- | This is some concrete implementation. +-- In this example we return a constant value. +getWeatherData :: Location -> Day -> IO WeatherData +getWeatherData _ _ = return $ WeatherData 30 diff --git a/simple/domain/WeatherReporter.hs b/simple/domain/WeatherReporter.hs new file mode 100644 index 0000000..bc0d214 --- /dev/null +++ b/simple/domain/WeatherReporter.hs @@ -0,0 +1,16 @@ +module WeatherReporter where + +import qualified WeatherProvider + +type WeatherReport = String + +-- | Domain logic. Usually some pure code that might use mtl, free monads, etc. +createWeatherReport :: WeatherProvider.WeatherData -> WeatherReport +createWeatherReport (WeatherProvider.WeatherData temp) = + "The current temperature in London is " ++ (show temp) + +-- | Domain logic that uses external dependency to get data and process it. +getCurrentWeatherReportInLondon :: IO WeatherReport +getCurrentWeatherReportInLondon = do + weatherData <- WeatherProvider.getWeatherData "London" "now" + return $ createWeatherReport weatherData diff --git a/simple/simple.cabal b/simple/simple.cabal new file mode 100644 index 0000000..3e84dad --- /dev/null +++ b/simple/simple.cabal @@ -0,0 +1,21 @@ +cabal-version: >=2 +name: simple +version: 0.1.0.0 +license-file: LICENSE +author: Evgenii Akentev +maintainer: i@ak3n.com +build-type: Simple +extra-source-files: CHANGELOG.md + +library domain + hs-source-dirs: domain + exposed-modules: WeatherProvider + , WeatherReporter + default-language: Haskell2010 + build-depends: base + +executable main + main-is: Main.hs + build-depends: base >=4.13 && <4.14 + , domain + default-language: Haskell2010