{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable, Rank2Types, ScopedTypeVariables, ViewPatterns #-}{-# LANGUAGE TypeFamilies #-}-- | A module for producing forward-defined build systems, in contrast to standard backwards-defined-- build systems such as shake. Based around ideas from <https://code.google.com/p/fabricate/ fabricate>.-- As an example:---- @-- import "Development.Shake"-- import "Development.Shake.Forward"-- import "Development.Shake.FilePath"---- main = 'shakeArgsForward' 'shakeOptions' $ do-- contents <- 'readFileLines' \"result.txt\"-- 'cache' $ 'cmd' \"tar -cf result.tar\" contents-- @---- Compared to backward-defined build systems (such as normal Shake), forward-defined build-- systems tend to be simpler for simple systems (less boilerplate, more direct style), but more-- complex for larger build systems (requires explicit parallelism, explicit sharing of build products,-- no automatic command line targets). As a general approach for writing forward-defined systems:---- * Figure out the sequence of system commands that will build your project.---- * Write a simple 'Action' that builds your project.---- * Insert 'cache' in front of most system commands.---- * Replace most loops with 'forP', where they can be executed in parallel.---- * Where Haskell performs real computation, if zero-build performance is insufficient, use 'cacheAction'.---- All forward-defined systems use 'AutoDeps', which requires @fsatrace@ to be on the @$PATH@.-- You can obtain @fsatrace@ from <https://github.com/jacereda/fsatrace>. You must set-- 'shakeLintInside' to specify where 'AutoDeps' will look for dependencies - if you want all dependencies-- everywhere use @[\"\"]@.---- This module is considered experimental - it has not been battle tested. There are now a few possible-- alternatives in this space:---- * Pier <http://hackage.haskell.org/package/pier/docs/Pier-Core-Artifact.html> (built on Shake).---- * Rattle <https://github.com/ndmitchell/rattle> (by the same author as Shake).---- * Stroll <https://github.com/snowleopard/stroll>.moduleDevelopment.Shake.Forward(shakeForward ,shakeArgsForward ,forwardOptions ,forwardRule ,cache ,cacheAction ,cacheActionWith ,)whereimportControl.MonadimportDevelopment.Shake importDevelopment.Shake.Rule importDevelopment.Shake.Command importDevelopment.Shake.Classes importDevelopment.Shake.FilePath importData.IORef.ExtraimportData.EitherimportData.TypeableimportData.List.ExtraimportControl.Exception.ExtraimportNumericimportSystem.IO.UnsafeimportData.BinaryimportqualifiedData.ByteStringasBSimportqualifiedData.ByteString.LazyasLBSimportqualifiedData.HashMap.StrictasMap{-# NOINLINEforwards #-}forwards ::IORef(Map.HashMapForward (Action Forward ))forwards :: IORef (HashMap Forward (Action Forward))
forwards =IO (IORef (HashMap Forward (Action Forward)))
-> IORef (HashMap Forward (Action Forward))
forall a. IO a -> a
unsafePerformIO(IO (IORef (HashMap Forward (Action Forward)))
 -> IORef (HashMap Forward (Action Forward)))
-> IO (IORef (HashMap Forward (Action Forward)))
-> IORef (HashMap Forward (Action Forward))
forall a b. (a -> b) -> a -> b
$HashMap Forward (Action Forward)
-> IO (IORef (HashMap Forward (Action Forward)))
forall a. a -> IO (IORef a)
newIORefHashMap Forward (Action Forward)
forall k v. HashMap k v
Map.empty-- I'd like to use TypeRep, but it doesn't have any instances in older versionsnewtypeForward =Forward (String,String,BS.ByteString)-- the type, the Show, the payloadderiving(Eq Forward
Eq Forward =>
(Int -> Forward -> Int) -> (Forward -> Int) -> Hashable Forward
Int -> Forward -> Int
Forward -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> Forward -> Int
hashWithSalt :: Int -> Forward -> Int
$chash :: Forward -> Int
hash :: Forward -> Int
Hashable,Typeable,Forward -> Forward -> Bool
(Forward -> Forward -> Bool)
-> (Forward -> Forward -> Bool) -> Eq Forward
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Forward -> Forward -> Bool
== :: Forward -> Forward -> Bool
$c/= :: Forward -> Forward -> Bool
/= :: Forward -> Forward -> Bool
Eq,Forward -> ()
(Forward -> ()) -> NFData Forward
forall a. (a -> ()) -> NFData a
$crnf :: Forward -> ()
rnf :: Forward -> ()
NFData,Get Forward
[Forward] -> Put
Forward -> Put
(Forward -> Put)
-> Get Forward -> ([Forward] -> Put) -> Binary Forward
forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
$cput :: Forward -> Put
put :: Forward -> Put
$cget :: Get Forward
get :: Get Forward
$cputList :: [Forward] -> Put
putList :: [Forward] -> Put
Binary)mkForward ::(Typeablea ,Showa ,Binarya )=>a ->Forward mkForward :: forall a. (Typeable a, Show a, Binary a) => a -> Forward
mkForward a
x =(String, String, ByteString) -> Forward
Forward (TypeRep -> String
forall a. Show a => a -> String
show(TypeRep -> String) -> TypeRep -> String
forall a b. (a -> b) -> a -> b
$a -> TypeRep
forall a. Typeable a => a -> TypeRep
typeOfa
x ,a -> String
forall a. Show a => a -> String
showa
x ,a -> ByteString
forall a. Binary a => a -> ByteString
encode' a
x )unForward ::foralla .(Typeablea ,Binarya )=>Forward ->a unForward :: forall a. (Typeable a, Binary a) => Forward -> a
unForward (Forward (String
got ,String
_,ByteString
x ))|String
got String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/=String
want =String -> a
forall a. Partial => String -> a
error(String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$String
"Failed to match forward type, wanted "String -> String -> String
forall a. [a] -> [a] -> [a]
++String -> String
forall a. Show a => a -> String
showString
want String -> String -> String
forall a. [a] -> [a] -> [a]
++String
", got "String -> String -> String
forall a. [a] -> [a] -> [a]
++String -> String
forall a. Show a => a -> String
showString
got |Bool
otherwise=ByteString -> a
forall a. Binary a => ByteString -> a
decode' ByteString
x wherewant :: String
want =TypeRep -> String
forall a. Show a => a -> String
show(TypeRep -> String) -> TypeRep -> String
forall a b. (a -> b) -> a -> b
$Proxy a -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep(Proxy a
forall {k} (t :: k). Proxy t
Proxy::Proxya )encode' ::Binarya =>a ->BS.ByteStringencode' :: forall a. Binary a => a -> ByteString
encode' =[ByteString] -> ByteString
BS.concat([ByteString] -> ByteString)
-> (a -> [ByteString]) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
.ByteString -> [ByteString]
LBS.toChunks(ByteString -> [ByteString])
-> (a -> ByteString) -> a -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.a -> ByteString
forall a. Binary a => a -> ByteString
encodedecode' ::Binarya =>BS.ByteString->a decode' :: forall a. Binary a => ByteString -> a
decode' =ByteString -> a
forall a. Binary a => ByteString -> a
decode(ByteString -> a) -> (ByteString -> ByteString) -> ByteString -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
.[ByteString] -> ByteString
LBS.fromChunks([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
.ByteString -> [ByteString]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
puretypeinstanceRuleResult Forward =Forward instanceShowForward whereshow :: Forward -> String
show(Forward (String
_,String
x ,ByteString
_))=String
x -- | Run a forward-defined build system.shakeForward ::ShakeOptions ->Action ()->IO()shakeForward :: ShakeOptions -> Action () -> IO ()
shakeForward ShakeOptions
opts Action ()
act =ShakeOptions -> Rules () -> IO ()
shake (ShakeOptions -> ShakeOptions
forwardOptions ShakeOptions
opts )(Action () -> Rules ()
forwardRule Action ()
act )-- | Run a forward-defined build system, interpreting command-line arguments.shakeArgsForward ::ShakeOptions ->Action ()->IO()shakeArgsForward :: ShakeOptions -> Action () -> IO ()
shakeArgsForward ShakeOptions
opts Action ()
act =ShakeOptions -> Rules () -> IO ()
shakeArgs (ShakeOptions -> ShakeOptions
forwardOptions ShakeOptions
opts )(Action () -> Rules ()
forwardRule Action ()
act )-- | Given an 'Action', turn it into a 'Rules' structure which runs in forward mode.forwardRule ::Action ()->Rules ()forwardRule :: Action () -> Rules ()
forwardRule Action ()
act =doShakeOptions
opts <-Rules ShakeOptions
getShakeOptionsRules Bool -> Rules () -> Rules ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null([String] -> Bool) -> [String] -> Bool
forall a b. (a -> b) -> a -> b
$ShakeOptions -> [String]
shakeLintInside ShakeOptions
opts )(Rules () -> Rules ()) -> Rules () -> Rules ()
forall a b. (a -> b) -> a -> b
$String -> Rules ()
forall a. String -> Rules a
forall (m :: * -> *) a. MonadFail m => String -> m a
failString
"When running in forward mode you must set shakeLintInside to specify where to detect dependencies"BuiltinLint Forward Forward
-> BuiltinIdentity Forward Forward
-> BuiltinRun Forward Forward
-> Rules ()
forall key value.
(RuleResult key ~ value, ShakeValue key, Typeable value,
 NFData value, Show value, Partial) =>
BuiltinLint key value
-> BuiltinIdentity key value -> BuiltinRun key value -> Rules ()
addBuiltinRule BuiltinLint Forward Forward
forall key value. BuiltinLint key value
noLint BuiltinIdentity Forward Forward
forall key value. BuiltinIdentity key value
noIdentity (BuiltinRun Forward Forward -> Rules ())
-> BuiltinRun Forward Forward -> Rules ()
forall a b. (a -> b) -> a -> b
$\Forward
k Maybe ByteString
old RunMode
mode ->caseMaybe ByteString
old ofJustByteString
old |RunMode
mode RunMode -> RunMode -> Bool
forall a. Eq a => a -> a -> Bool
==RunMode
RunDependenciesSame ->RunResult Forward -> Action (RunResult Forward)
forall a. a -> Action a
forall (f :: * -> *) a. Applicative f => a -> f a
pure(RunResult Forward -> Action (RunResult Forward))
-> RunResult Forward -> Action (RunResult Forward)
forall a b. (a -> b) -> a -> b
$RunChanged -> ByteString -> Forward -> RunResult Forward
forall value. RunChanged -> ByteString -> value -> RunResult value
RunResult RunChanged
ChangedNothing ByteString
old (ByteString -> Forward
forall a. Binary a => ByteString -> a
decode' ByteString
old )Maybe ByteString
_->doMaybe (Action Forward)
res <-IO (Maybe (Action Forward)) -> Action (Maybe (Action Forward))
forall a. IO a -> Action a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO(IO (Maybe (Action Forward)) -> Action (Maybe (Action Forward)))
-> IO (Maybe (Action Forward)) -> Action (Maybe (Action Forward))
forall a b. (a -> b) -> a -> b
$IORef (HashMap Forward (Action Forward))
-> (HashMap Forward (Action Forward)
 -> (HashMap Forward (Action Forward), Maybe (Action Forward)))
-> IO (Maybe (Action Forward))
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORefIORef (HashMap Forward (Action Forward))
forwards ((HashMap Forward (Action Forward)
 -> (HashMap Forward (Action Forward), Maybe (Action Forward)))
 -> IO (Maybe (Action Forward)))
-> (HashMap Forward (Action Forward)
 -> (HashMap Forward (Action Forward), Maybe (Action Forward)))
-> IO (Maybe (Action Forward))
forall a b. (a -> b) -> a -> b
$\HashMap Forward (Action Forward)
mp ->(Forward
-> HashMap Forward (Action Forward)
-> HashMap Forward (Action Forward)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
Map.deleteForward
k HashMap Forward (Action Forward)
mp ,Forward
-> HashMap Forward (Action Forward) -> Maybe (Action Forward)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
Map.lookupForward
k HashMap Forward (Action Forward)
mp )caseMaybe (Action Forward)
res ofMaybe (Action Forward)
Nothing->IO (RunResult Forward) -> Action (RunResult Forward)
forall a. IO a -> Action a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO(IO (RunResult Forward) -> Action (RunResult Forward))
-> IO (RunResult Forward) -> Action (RunResult Forward)
forall a b. (a -> b) -> a -> b
$String -> IO (RunResult Forward)
forall a. Partial => String -> IO a
errorIO(String -> IO (RunResult Forward))
-> String -> IO (RunResult Forward)
forall a b. (a -> b) -> a -> b
$String
"Failed to find action name, "String -> String -> String
forall a. [a] -> [a] -> [a]
++Forward -> String
forall a. Show a => a -> String
showForward
k JustAction Forward
act ->doForward
new <-Action Forward
act RunResult Forward -> Action (RunResult Forward)
forall a. a -> Action a
forall (f :: * -> *) a. Applicative f => a -> f a
pure(RunResult Forward -> Action (RunResult Forward))
-> RunResult Forward -> Action (RunResult Forward)
forall a b. (a -> b) -> a -> b
$RunChanged -> ByteString -> Forward -> RunResult Forward
forall value. RunChanged -> ByteString -> value -> RunResult value
RunResult RunChanged
ChangedRecomputeSame (Forward -> ByteString
forall a. Binary a => a -> ByteString
encode' Forward
new )Forward
new Action () -> Rules ()
forall a. Partial => Action a -> Rules ()
action Action ()
act -- | Given a 'ShakeOptions', set the options necessary to execute in forward mode.forwardOptions ::ShakeOptions ->ShakeOptions forwardOptions :: ShakeOptions -> ShakeOptions
forwardOptions ShakeOptions
opts =ShakeOptions
opts {shakeCommandOptions =[AutoDeps ]}-- | Cache an action, given a key and an 'Action'. Each call in your program should specify a different-- key, but the key should remain consistent between runs. Ideally, the 'Action' will gather all its dependencies-- with tracked operations, e.g. 'readFile\''. However, if information is accessed from the environment-- (e.g. the action is a closure), you should call 'cacheActionWith' being explicit about what is captured.cacheAction ::(Typeablea ,Binarya ,Showa ,Typeableb ,Binaryb ,Showb )=>a ->Action b ->Action b cacheAction :: forall a b.
(Typeable a, Binary a, Show a, Typeable b, Binary b, Show b) =>
a -> Action b -> Action b
cacheAction (a -> Forward
forall a. (Typeable a, Show a, Binary a) => a -> Forward
mkForward ->Forward
key )(Action b
action ::Action b )=doIO () -> Action ()
forall a. IO a -> Action a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO(IO () -> Action ()) -> IO () -> Action ()
forall a b. (a -> b) -> a -> b
$IORef (HashMap Forward (Action Forward))
-> (HashMap Forward (Action Forward)
 -> HashMap Forward (Action Forward))
-> IO ()
forall a. IORef a -> (a -> a) -> IO ()
atomicModifyIORef_IORef (HashMap Forward (Action Forward))
forwards ((HashMap Forward (Action Forward)
 -> HashMap Forward (Action Forward))
 -> IO ())
-> (HashMap Forward (Action Forward)
 -> HashMap Forward (Action Forward))
-> IO ()
forall a b. (a -> b) -> a -> b
$Forward
-> Action Forward
-> HashMap Forward (Action Forward)
-> HashMap Forward (Action Forward)
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
Map.insertForward
key (b -> Forward
forall a. (Typeable a, Show a, Binary a) => a -> Forward
mkForward (b -> Forward) -> Action b -> Action Forward
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>Action b
action )Forward
res <-Forward -> Action Forward
forall key value.
(Partial, RuleResult key ~ value, ShakeValue key,
 Typeable value) =>
key -> Action value
apply1 Forward
key IO () -> Action ()
forall a. IO a -> Action a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO(IO () -> Action ()) -> IO () -> Action ()
forall a b. (a -> b) -> a -> b
$IORef (HashMap Forward (Action Forward))
-> (HashMap Forward (Action Forward)
 -> HashMap Forward (Action Forward))
-> IO ()
forall a. IORef a -> (a -> a) -> IO ()
atomicModifyIORef_IORef (HashMap Forward (Action Forward))
forwards ((HashMap Forward (Action Forward)
 -> HashMap Forward (Action Forward))
 -> IO ())
-> (HashMap Forward (Action Forward)
 -> HashMap Forward (Action Forward))
-> IO ()
forall a b. (a -> b) -> a -> b
$Forward
-> HashMap Forward (Action Forward)
-> HashMap Forward (Action Forward)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
Map.deleteForward
key b -> Action b
forall a. a -> Action a
forall (f :: * -> *) a. Applicative f => a -> f a
pure(b -> Action b) -> b -> Action b
forall a b. (a -> b) -> a -> b
$Forward -> b
forall a. (Typeable a, Binary a) => Forward -> a
unForward Forward
res newtypeWith a =With a deriving(Typeable,Get (With a)
[With a] -> Put
With a -> Put
(With a -> Put)
-> Get (With a) -> ([With a] -> Put) -> Binary (With a)
forall a. Binary a => Get (With a)
forall a. Binary a => [With a] -> Put
forall a. Binary a => With a -> Put
forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
$cput :: forall a. Binary a => With a -> Put
put :: With a -> Put
$cget :: forall a. Binary a => Get (With a)
get :: Get (With a)
$cputList :: forall a. Binary a => [With a] -> Put
putList :: [With a] -> Put
Binary,Int -> With a -> String -> String
[With a] -> String -> String
With a -> String
(Int -> With a -> String -> String)
-> (With a -> String)
-> ([With a] -> String -> String)
-> Show (With a)
forall a. Show a => Int -> With a -> String -> String
forall a. Show a => [With a] -> String -> String
forall a. Show a => With a -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: forall a. Show a => Int -> With a -> String -> String
showsPrec :: Int -> With a -> String -> String
$cshow :: forall a. Show a => With a -> String
show :: With a -> String
$cshowList :: forall a. Show a => [With a] -> String -> String
showList :: [With a] -> String -> String
Show)-- | Like 'cacheAction', but also specify which information is captured by the closure of the 'Action'. If that-- information changes, the 'Action' will be rerun.cacheActionWith ::(Typeablea ,Binarya ,Showa ,Typeableb ,Binaryb ,Showb ,Typeablec ,Binaryc ,Showc )=>a ->b ->Action c ->Action c cacheActionWith :: forall a b c.
(Typeable a, Binary a, Show a, Typeable b, Binary b, Show b,
 Typeable c, Binary c, Show c) =>
a -> b -> Action c -> Action c
cacheActionWith a
key b
argument Action c
action =doWith b -> Action b -> Action b
forall a b.
(Typeable a, Binary a, Show a, Typeable b, Binary b, Show b) =>
a -> Action b -> Action b
cacheAction (b -> With b
forall a. a -> With a
With b
argument )(Action b -> Action b) -> Action b -> Action b
forall a b. (a -> b) -> a -> b
$doAction ()
alwaysRerun b -> Action b
forall a. a -> Action a
forall (f :: * -> *) a. Applicative f => a -> f a
pureb
argument a -> Action c -> Action c
forall a b.
(Typeable a, Binary a, Show a, Typeable b, Binary b, Show b) =>
a -> Action b -> Action b
cacheAction a
key (Action c -> Action c) -> Action c -> Action c
forall a b. (a -> b) -> a -> b
$doForward -> Action Forward
forall key value.
(Partial, RuleResult key ~ value, ShakeValue key,
 Typeable value) =>
key -> Action value
apply1 (Forward -> Action Forward) -> Forward -> Action Forward
forall a b. (a -> b) -> a -> b
$With b -> Forward
forall a. (Typeable a, Show a, Binary a) => a -> Forward
mkForward (With b -> Forward) -> With b -> Forward
forall a b. (a -> b) -> a -> b
$b -> With b
forall a. a -> With a
With b
argument Action c
action -- | Apply caching to an external command using the same arguments as 'cmd'.---- > cache $ cmd "gcc -c" ["foo.c"] "-o" ["foo.o"]---- This command will be cached, with the inputs/outputs traced. If any of the-- files used by this command (e.g. @foo.c@ or header files it imports) then-- the command will rerun.cache ::(forallr .CmdArguments r =>r )->Action ()cache :: (forall r. CmdArguments r => r) -> Action ()
cache forall r. CmdArguments r => r
cmd =doletCmdArgument [Either CmdOption String]
args =CmdArgument
forall r. CmdArguments r => r
cmd letisDull :: String -> Bool
isDull [Char
'-',Char
_]=Bool
True;isDull String
_=Bool
Falseletname :: String
name =String -> [String] -> String
forall a. a -> [a] -> a
headDefString
"unknown"([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$(String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter(Bool -> Bool
not(Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.String -> Bool
isDull )([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$[String] -> [String]
forall a. [a] -> [a]
drop1([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$[Either CmdOption String] -> [String]
forall a b. [Either a b] -> [b]
rights[Either CmdOption String]
args Command -> Action () -> Action ()
forall a b.
(Typeable a, Binary a, Show a, Typeable b, Binary b, Show b) =>
a -> Action b -> Action b
cacheAction (String -> Command
Command (String -> Command) -> String -> Command
forall a b. (a -> b) -> a -> b
$String -> String
toStandard String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++String
" #"String -> String -> String
forall a. [a] -> [a] -> [a]
++String -> String
upper(Int -> String -> String
forall a. Integral a => a -> String -> String
showHex(Int -> Int
forall a. Num a => a -> a
abs(Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$String -> Int
forall a. Hashable a => a -> Int
hash(String -> Int) -> String -> Int
forall a b. (a -> b) -> a -> b
$[Either CmdOption String] -> String
forall a. Show a => a -> String
show[Either CmdOption String]
args )String
""))Action ()
forall r. CmdArguments r => r
cmd newtypeCommand =Command Stringderiving(Typeable,Get Command
[Command] -> Put
Command -> Put
(Command -> Put)
-> Get Command -> ([Command] -> Put) -> Binary Command
forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
$cput :: Command -> Put
put :: Command -> Put
$cget :: Get Command
get :: Get Command
$cputList :: [Command] -> Put
putList :: [Command] -> Put
Binary)instanceShowCommand whereshow :: Command -> String
show(Command String
x )=String
"command "String -> String -> String
forall a. [a] -> [a] -> [a]
++String
x 

AltStyle によって変換されたページ (->オリジナル) /