General
Type annotations
- Always use it (unless it interferes with compilation)
- Example:
producerPath :: Text
producerPath = "/home/atidot/platform/testDockers/producer"
Space your code
producerPath :: Text
producerPath = "/home/atidot/platform/testDockers/producer"
consumerPath :: Text
consumerPath = "/home/atidot/platform/testDockers/consumer"
launch :: Sh ()
launch "atidot/producer" = dummyLaunch -- startDockerLocal producerPath
launch "atidot/consumer" = pure () --startDockerLocal consumerPath
Qualified Imports
- Use it instead of full package path
- Example:
import "text" Data.Text hiding (drop)
import qualified "text" Data.Text as T (drop)
startDockerLocal :: Text -> Text
startDockerLocal = T.drop 7
Imports
- Use
{-# LANGUAGE PackageImports #-}
(package name)
- Align
- Leave room for
qualified
if you use that
- Import only what you need when you can
- Sort imports, by package and by generality
base
is always first
Control.
and Data.
are after
- Last are your project's packages
- Example:
{-# LANGUAGE PackageImports #-}
import "base" Control.Monad.IO.Class (liftIO)
import "base" Data.Monoid ((<>))
import "lens" Control.Lens
import qualified "bytestring" Data.ByteString.Char8 as B (unpack)
import qualified "text" Data.Text as T (pack)
import "platform-types" Platform.Types
Records
- Align
- Prefix fields with
_myDataType_
(for data MyDataType
)
- Use
{-# LANGUAGE BangPatterns #-}
- !
- Derive
Show
, Read
, Eq
, Ord
, Enum
, Bounded
when possible
- Derive
Typeable
, Data
, Generic
when possible
- Example:
{-# LANGUAGE BangPatterns #-}
import "base" GHC.Generics (Generic)
import "base" Data.Typeable (Typeable)
import "base" Data.Data (Data)
data Direction
= North
| East
| South
| West
deriving (Show, Read, Eq, Ord, Enum, Bounded, Typeable, Data, Generic)
data Turtle
= Turtle
{ _turtle_x :: !Int
, _turtle_y :: !Int
, _turtle_vX :: !Int
, _turtle_vY :: !Int
, _turtle_head :: !Direction
, _turtle_name :: !(Maybe String)
} deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)
Function Arguments
- Align (when more than
arg -> return
)
- This is also useful for adding Haddock comments later
- Example:
connect :: Text
-> Text
-> Sh ()
Specific
Docker integration
- Don't assume
/usr/bin/docker
is always there. In NixOS for example it's not
16:09 barak@berkos:~ $ ls -la /usr/bin
lrwxrwxrwx 66 root 13 Nov 23:48 env -> /nix/store/d9s1kq1bnwqgxwcvv4zrc36ysnxg8gv7-coreutils-8.30/bin/env
16:09 barak@berkos:~ $
- For talking to Docker we may want to use this package: http://hackage.haskell.org/package/docker (or a similar one) instead of "reinventing the wheel" here
- Repeating the
run_ docker
is tedious and too verbose (am I missing the upside?). why not:
data DockerCommand
= Build
| Pull
| Start
deriving (Show, Read, Eq, Ord, Enum, Bounded, Typeable, Data, Generic)
docker :: DockerCommand
-> [Text]
-> Sh ()
docker command args'
= run_ (fromText "docker") args
where
args :: [Text]
args = [T.toLower . T.pack . show $ command]
<> args'