Last active
December 30, 2015 09:18
-
-
Save jtbandes/c8adf9ab67ea636a2592 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Control.Arrow ( (&&&) ) | |
import qualified Control.Arrow ( first, second ) | |
import Data.Maybe ( fromMaybe ) | |
-- this also exists in Data.Graph.Inductive.Query.Monad | |
(><) :: (a -> c) -> (b -> d) -> (a, b) -> (c, d) | |
(><) f g = Control.Arrow.first f . Control.Arrow.second g | |
first :: [a] -> Maybe a | |
first [] = Nothing | |
first (x:_) = Just x | |
rest :: [a] -> [a] | |
rest [] = error "scoundrel!" | |
rest (_:xs) = xs | |
data Command = Cmd deriving (Show) -- or something more useful | |
lookUpCommand :: String -> Maybe Command | |
lookUpCommand = undefined -- or something more useful | |
fallbackCommand = Cmd -- or something more useful | |
commandAndRemainingArgs :: [String] -> (Command, [String]) | |
commandAndRemainingArgs args = | |
let commandName = first args in | |
let maybeCommandAndMaybeRest = ((>>= lookUpCommand) &&& ((rest args) <$)) commandName in | |
let commandAndRest = (fromMaybe fallbackCommand >< fromMaybe []) maybeCommandAndMaybeRest in | |
commandAndRest |
gibiansky
commented
Dec 2, 2015
alternative using Safe
:
import Data.Maybe (fromMaybe)
import Safe (tailDef, headMay)
data Command = Cmd deriving (Show) -- or something more useful
lookUpCommand :: String -> Maybe Command
lookUpCommand = undefined -- or something more useful
fallbackCommand = Cmd -- or something more useful
commandAndRemainingArgs :: [String] -> (Command, [String])
commandAndRemainingArgs strings = (command, args)
where
command = fromMaybe fallbackCommand (headMay args >>= lookUpCommand)
args = tailDef [] strs
struct Command {}
let fallbackCommand = Command()
func lookUpCommand(name: String) -> Command? { fatalError("some impl here") }
func version1(args: [String]) -> (Command, [String]) {
let cmd: Command
let rest: [String]
// fairly annoying
if let name = args.first {
cmd = lookUpCommand(name) ?? fallbackCommand
rest = Array(args.suffixFrom(1))
}
else {
cmd = fallbackCommand
rest = []
}
return (cmd, rest)
}
// or...
func version2(args: [String]) -> (Command, [String]) {
let cmd = args.first.flatMap(lookUpCommand) ?? fallbackCommand
let rest = args.isEmpty ? [] : Array(args.suffixFrom(1)) // mildly annoying
return (cmd, rest)
}
While my original using >>=
/ &&&
/ <$
/ ><
is horrible, I like that it makes a very clear pipeline:
lookUpCommand fallbackCommand
first Command? --> Command
input [String] --> String? <
[String]? --> [String]
rest fallback to []
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment