How can I avoid writing boilerplate code for functions performing pattern matching?

前端 未结 3 650
逝去的感伤
逝去的感伤 2021-02-14 13:54

In this response to another question, a little Haskell code sketch was given which uses wrapper functions to factor out some code for doing syntax checking on command line argum

3条回答
  •  北海茫月
    2021-02-14 14:37

    Combinators are your friend. Try this:

    take1 :: [String] -> Maybe String
    take1 [x] = Just x
    take1 _ = Nothing
    
    take2 :: [String] -> Maybe (String,String)
    take2 [x,y] = Just (x,y)
    take2 _ = Nothing
    
    take3 :: [String] -> Maybe ((String,String),String)
    take3 [x,y,z] = Just ((x,y),z)
    take3 _ = Nothing
    
    type ErrorMsg = String
    
    with1 :: (String -> IO ()) -> ErrorMsg -> [String] -> IO ()
    with1 f msg = maybe (fail msg) f . take1
    
    with2 :: (String -> String -> IO ()) -> ErrorMsg -> [String] -> IO ()
    with2 f msg = maybe (fail msg) (uncurry f) . take2
    
    with3 :: (String -> String -> String -> IO ()) -> ErrorMsg -> [String] -> IO ()
    with3 f msg = maybe (fail msg) (uncurry . uncurry $ f) . take3
    
    foo a b c = putStrLn $ a ++ " :: " ++ b ++ " = " ++ c
    
    bar = with3 foo "You must send foo a name, type, definition"
    
    main = do
      bar [ "xs", "[Int]", "[1..3]" ]
      bar [ "xs", "[Int]", "[1..3]", "What am I doing here?" ]
    

    And if you like overpowered language extensions:

    {-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
    
    foo a b c = putStrLn $ a ++ " :: " ++ b ++ " = " ++ c
    foo_msg = "You must send foo a name, type, definition"
    
    class ApplyArg a b | a -> b where
      appArg :: ErrorMsg -> a -> [String] -> IO b
    
    instance ApplyArg (IO b) b where
      appArg _msg todo [] = todo
      appArg msg _todo _ = fail msg
    
    instance ApplyArg v q => ApplyArg (String -> v) q where
      appArg msg todo (x:xs) = appArg msg (todo x) xs
      appArg msg _todo _ = fail msg
    
    quux :: [String] -> IO ()
    quux xs = appArg foo_msg foo xs
    
    main = do
      quux [ "xs", "[int]", "[1..3]" ]
      quux [ "xs", "[int]", "[1..3]", "what am i doing here?" ]
    

提交回复
热议问题