Haskell Yahoo Finance命令行工具

Haskell Yahoo Finance命令行工具,haskell,command-line-arguments,yahoo,haskell-platform,yahoo-finance,Haskell,Command Line Arguments,Yahoo,Haskell Platform,Yahoo Finance,我正在尝试使用创建一个命令行工具,它将从yahoo finance获取一个符号的引用。当我试图编译时,我收到了这个错误 Couldn't match expected type `[t0]' with actual type `IO (Maybe (Map (QuoteSymbol, QuoteField) QuoteValue))' In the return type of a c

我正在尝试使用创建一个命令行工具,它将从yahoo finance获取一个符号的引用。当我试图编译时,我收到了这个错误

Couldn't match expected type `[t0]'
                with actual type `IO
                                    (Maybe (Map (QuoteSymbol, QuoteField) QuoteValue))'
    In the return type of a call of `getQuote'
    In a stmt of a 'do' expression:
        q <- getQuote [arg] ["s", "l1", "c"]
    In the expression:
      do { q <- getQuote [arg] ["s", "l1", ....];
           case q of {
             Nothing -> error "symbol not found"
             Just m -> m } }
无法匹配预期的类型“[t0]”
使用实际类型'IO
(可能是(映射(QuoteSymbol,QuoteField)QuoteValue)'
在调用“getQuote”的返回类型中
在“do”表达式的stmt中:
q m}}
我刚刚开始学习haskell,这是一种非常不同但功能强大的语言,我不太明白问题出在哪里。任何帮助都将不胜感激,如果我用“haskell”的方式做这件事,如果没有任何改进,我也将不胜感激。谢谢

module Main where

import Finance.Quote.Yahoo
import Data.Time.Calendar
import Data.Map
import System( getArgs )
import System.Console.GetOpt
import Data.Maybe ( fromMaybe )

data Options = Options
    { optVerbose     :: Bool
    , optShowVersion :: Bool
    , optOutput      :: Maybe FilePath
    , optInput       :: Maybe FilePath
    , optLibDirs     :: [FilePath]
    , optSymbol      :: String
    } deriving Show

defaultOptions    = Options
    { optVerbose     = False
    , optShowVersion = False
    , optOutput      = Nothing
    , optInput       = Nothing
    , optLibDirs     = []
    , optSymbol      = "YHOO"
    }

options :: [OptDescr (Options -> Options)]
options =
    [ Option ['v']     ["verbose"]
        (NoArg (\ opts -> opts { optVerbose = True }))
        "chatty output on stderr"
    , Option ['V','?'] ["version"]
        (NoArg (\ opts -> opts { optShowVersion = True }))
        "show version number"
    , Option ['o']     ["output"]
        (OptArg ((\ f opts -> opts { optOutput = Just f }) . fromMaybe "output")
        "FILE")
        "output FILE"
    , Option ['c']     []
        (OptArg ((\ f opts -> opts { optInput = Just f }) . fromMaybe "input")
        "FILE")
        "input FILE"
    , Option ['L']     ["libdir"]
        (ReqArg (\ d opts -> opts { optLibDirs = optLibDirs opts ++ [d] }) "DIR")
        "library directory"
    , Option ['s']     ["symbol"]
        (ReqArg (\ s opts -> opts { optSymbol = getSymbol s }) "SYMBOL")
        "symbol SYMBOL"
    ]

compilerOpts :: [String] -> IO (Options, [String])
compilerOpts argv =
    case getOpt Permute options argv of
        (o,n,[]  ) -> return (foldl (flip id) defaultOptions o, n)
        (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options))
    where header = "Usage: ic [OPTION...] files..."

main = do
    args <- getArgs
    compilerOpts args

getSymbol :: String -> String
getSymbol arg = do 
  q <- getQuote [arg] ["s", "l1", "c"] 
  case q of
    Nothing -> error "symbol not found"
    Just m -> m
modulemain其中
import Finance.Quote.Yahoo
导入Data.Time.Calendar
导入数据。映射
导入系统(getArgs)
导入System.Console.GetOpt
导入数据。可能(来自可能)
数据选项=选项
{optVerbose::Bool
,optShowVersion::Bool
,optOutput::可能是文件路径
,optInput::可能是文件路径
,optLibDirs::[FilePath]
,optSymbol::String
}衍生节目
defaultOptions=选项
{optVerbose=False
,optShowVersion=False
,光电输出=无
,optInput=Nothing
,optLibDirs=[]
,optSymbol=“YHOO”
}
选项::[OptDescr(选项->选项)]
选择权=
[选项['v'][“详细”]
(NoArg(\opts->opts{optVerbose=True}))
“stderr上的聊天输出”
,选项['V','?'][“版本”]
(NoArg(\opts->opts{optShowVersion=True}))
“显示版本号”
,选项['o'][“输出”]
(OptArg((\f opts->opts{optOutput=Just f}).fromaybe“output”)
“文件”)
“输出文件”
,选项['c'][]
(OptArg((\f opts->opts{optInput=Just f}).fromMaybe“input”)
“文件”)
“输入文件”
,选项['L'][“libdir”]
(ReqArg(\d opts->opts{optLibDirs=optLibDirs opts++[d]})“DIR”)
“库目录”
,选项['s'][“符号”]
(ReqArg(\s opts->opts{optSymbol=getSymbol s})“SYMBOL”)
“符号”
]
编译器提示::[String]->IO(选项,[String])
编译指针argv=
案例getOpt排列选项argv of
(o,n,[])->返回(foldl(翻转id)默认选项o,n)
(u,u,errs)->ioError(userError(concat errs++usageInfo头选项))
其中header=“用法:ic[选项…]文件…”
main=do
args字符串
getSymbol arg=do
q错误“未找到符号”
只是m->m
这是错误的:

getSymbol :: String -> String
getSymbol arg = do 
  q <- getQuote [arg] ["s", "l1", "c"] 
  case q of
    Nothing -> error "symbol not found"
    Just m -> m
getSymbol::String->String
getSymbol arg=do
q错误“未找到符号”
只是m->m
可能是:

getSymbol :: String -> IO String
getSymbol arg = do 
  q <- getQuote [arg] ["s", "l1", "c"] 
  case q of
    Nothing -> fail "symbol not found"
    Just m -> return m
getSymbol::String->IO字符串
getSymbol arg=do
q失败“未找到符号”
只需m->返回m
注意,我已经更改了类型签名和最后两行。(由于我已更改了
getSymbol
的类型,因此无论在何处调用,都必须以不同的方式使用结果。)

部分解释:

您正在使用
do
语法,这将产生一个一元值。
getSymbol
的返回类型是
String
,与
[Char]
相同。列表是单子,所以这很好


但是,当您调用
右侧的
getQuote
时,问题在于
getSymbol
选项的定义无关,因为它是一个
IO
操作,从它使用
getQuote
的事实可以看出:

getQuote :: [QuoteSymbol] 
         -> [QuoteField]   
         -> IO (Maybe (Map (QuoteSymbol, QuoteField) QuoteValue))
因此,当您说
optSymbol=getSymbol s
时,您应该只放置字符串s。关键的一行当然应该是

(ReqArg (\ s opts -> opts { optSymbol =  s }) "SYMBOL")
不是

目前,您只是在分析参数。您对
optSymbol
字符串所做的操作(例如,通过
getSymbol
到Yahoo了解该字符串)属于
main
或需要定义的一些初步操作。这是一个进行类型检查的模块,它几乎什么都不做,表现如下:

-- $ ./yahoo -s STD.F  -- Standard Chartered?
-- STD.F c -0.396 - -1.99%
-- STD.F l1 19.492
-- STD.F s STD.F

module Main where

import Finance.Quote.Yahoo
import Data.Time.Calendar
import Data.Map
import Prelude
import qualified Prelude
import System.Environment( getArgs )
import System.Console.GetOpt
import Data.Maybe ( fromMaybe )
import System.IO.Unsafe

main = do
    args <- getArgs
    (options, strs) <- compilerOpts args
    whatIDoWithTheUsersOptions options strs

-- This is not doing much with all this user input ...
whatIDoWithTheUsersOptions :: Options -> [String] -> IO ()
whatIDoWithTheUsersOptions options strs = do
    blather <- getSymbol $ optSymbol options
    putStrLn blather

getSymbol :: String ->  IO String
getSymbol arg =   do
  q <- getQuote [arg] ["s", "l1", "c"] 
  case q of
    Nothing -> return $ "symbol " ++ arg ++ " not found"
    Just m -> return $ unlines $ Prelude.map helper (toList m)
 where helper ((a,b), c) = unwords [a,b,c]


data Options = Options
    { optVerbose     :: Bool
    , optShowVersion :: Bool
    , optOutput      :: Maybe FilePath
    , optInput       :: Maybe FilePath
    , optLibDirs     :: [FilePath]
    , optSymbol      :: String
    } deriving Show

defaultOptions    = Options
    { optVerbose     = False
    , optShowVersion = False
    , optOutput      = Nothing
    , optInput       = Nothing
    , optLibDirs     = []
    , optSymbol      = "YHOO"
    }

options :: [OptDescr (Options -> Options)]
options =
    [ Option ['v']     ["verbose"]
        (NoArg (\ opts -> opts { optVerbose = True }))
        "chatty output on stderr"
    , Option ['V','?'] ["version"]
        (NoArg (\ opts -> opts { optShowVersion = True }))
        "show version number"
    , Option ['o']     ["output"]
        (OptArg ((\ f opts -> opts { optOutput = Just f }) . fromMaybe "output")
        "FILE")
        "output FILE"
    , Option ['c']     []
        (OptArg ((\ f opts -> opts { optInput = Just f }) . fromMaybe "input")
        "FILE")
        "input FILE"
    , Option ['L']     ["libdir"]
        (ReqArg (\ d opts -> opts { optLibDirs = optLibDirs opts ++ [d] }) "DIR")
        "library directory"
    , Option ['s']     ["symbol"]
        (ReqArg (\ s opts -> opts { optSymbol =  s }) "SYMBOL")
        "symbol SYMBOL"
    ]

compilerOpts :: [String] -> IO (Options, [String])
compilerOpts argv =
    case getOpt Permute options argv of
        (o,n,[]  ) -> return (Prelude.foldl (flip id) defaultOptions o, n)
        (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options))
    where header = "Usage: ic [OPTION...] files..."
--$./yahoo-s标准F--渣打银行?
--标准食品成本-0.396--1.99%
--标准F l1 19.492
--标准频率标准频率
模块主要在哪里
import Finance.Quote.Yahoo
导入Data.Time.Calendar
导入数据。映射
进口序曲
进口合格前奏曲
导入System.Environment(getArgs)
导入System.Console.GetOpt
导入数据。可能(来自可能)
导入System.IO不安全
main=do
args IO()
用户选项选项strs=do的作用是什么
胡言乱语
getSymbol arg=do
q返回$“符号”++arg++“未找到”
Just m->return$unlines$Prelude.map助手(toList m)
其中helper((a,b,c)=UNWORD[a,b,c]
数据选项=选项
{optVerbose::Bool
,optShowVersion::Bool
,optOutput::可能是文件路径
,optInput::可能是文件路径
,optLibDirs::[FilePath]
,optSymbol::String
}衍生节目
defaultOptions=选项
{optVerbose=False
,optShowVersion=False
,光电输出=无
,optInput=Nothing
,optLibDirs=[]
,optSymbol=“YHOO”
}
选项::[OptDescr(选项->选项)]
选择权=
[选项['v'][“详细”]
(NoArg(\opts->opts{optVerbose=True}))
“stderr上的聊天输出”
,选项['V','?'][“版本”]
(NoArg(\opts->opts{optShowVersion=True}))
“显示版本号”
,选项['o'][“输出”]
(OptArg((\f opts->opts{optOutput=Just f}).fromaybe“output”)
“文件”)
“输出文件”
,选项['c'][]
(OptArg((\f opts->opts{optInput=Just f}).fromMaybe“input”)
“文件”)
“输入文件”
,选项['L'][“libdir”]
(ReqArg(\d opts->opts{optLibDirs=optLibDirs opts++[d]})“DIR”)
-- $ ./yahoo -s STD.F  -- Standard Chartered?
-- STD.F c -0.396 - -1.99%
-- STD.F l1 19.492
-- STD.F s STD.F

module Main where

import Finance.Quote.Yahoo
import Data.Time.Calendar
import Data.Map
import Prelude
import qualified Prelude
import System.Environment( getArgs )
import System.Console.GetOpt
import Data.Maybe ( fromMaybe )
import System.IO.Unsafe

main = do
    args <- getArgs
    (options, strs) <- compilerOpts args
    whatIDoWithTheUsersOptions options strs

-- This is not doing much with all this user input ...
whatIDoWithTheUsersOptions :: Options -> [String] -> IO ()
whatIDoWithTheUsersOptions options strs = do
    blather <- getSymbol $ optSymbol options
    putStrLn blather

getSymbol :: String ->  IO String
getSymbol arg =   do
  q <- getQuote [arg] ["s", "l1", "c"] 
  case q of
    Nothing -> return $ "symbol " ++ arg ++ " not found"
    Just m -> return $ unlines $ Prelude.map helper (toList m)
 where helper ((a,b), c) = unwords [a,b,c]


data Options = Options
    { optVerbose     :: Bool
    , optShowVersion :: Bool
    , optOutput      :: Maybe FilePath
    , optInput       :: Maybe FilePath
    , optLibDirs     :: [FilePath]
    , optSymbol      :: String
    } deriving Show

defaultOptions    = Options
    { optVerbose     = False
    , optShowVersion = False
    , optOutput      = Nothing
    , optInput       = Nothing
    , optLibDirs     = []
    , optSymbol      = "YHOO"
    }

options :: [OptDescr (Options -> Options)]
options =
    [ Option ['v']     ["verbose"]
        (NoArg (\ opts -> opts { optVerbose = True }))
        "chatty output on stderr"
    , Option ['V','?'] ["version"]
        (NoArg (\ opts -> opts { optShowVersion = True }))
        "show version number"
    , Option ['o']     ["output"]
        (OptArg ((\ f opts -> opts { optOutput = Just f }) . fromMaybe "output")
        "FILE")
        "output FILE"
    , Option ['c']     []
        (OptArg ((\ f opts -> opts { optInput = Just f }) . fromMaybe "input")
        "FILE")
        "input FILE"
    , Option ['L']     ["libdir"]
        (ReqArg (\ d opts -> opts { optLibDirs = optLibDirs opts ++ [d] }) "DIR")
        "library directory"
    , Option ['s']     ["symbol"]
        (ReqArg (\ s opts -> opts { optSymbol =  s }) "SYMBOL")
        "symbol SYMBOL"
    ]

compilerOpts :: [String] -> IO (Options, [String])
compilerOpts argv =
    case getOpt Permute options argv of
        (o,n,[]  ) -> return (Prelude.foldl (flip id) defaultOptions o, n)
        (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options))
    where header = "Usage: ic [OPTION...] files..."