Haskell Yahoo Finance Инструмент командной строки - PullRequest
3 голосов
/ 21 марта 2012

Я пытаюсь использовать этот модуль , чтобы создать инструмент командной строки, который будет получать цитату из 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 } }

Я только начинаю изучать 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

Ответы [ 2 ]

1 голос
/ 21 марта 2012

Проблема в том, что getSymbol не имеет никакого смысла в определении options, поскольку это действие IO, как мы можем видеть из факта, что он использует getQuote:

getQuote :: [QuoteSymbol] 
         -> [QuoteField]   
         -> IO (Maybe (Map (QuoteSymbol, QuoteField) QuoteValue))

Так что, где вы говорите optSymbol = getSymbol s, вы должны просто поместить строку s.Важная строка должна определенно читать

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

, а не

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

В данный момент вы просто анализируете аргументы.То, что вы делаете со строкой optSymbol - например, перейдите в Yahoo, чтобы узнать об этом через getSymbol, - относится к 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..."
1 голос
/ 21 марта 2012

Это неправильно:

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 -> IO String
getSymbol arg = do 
  q <- getQuote [arg] ["s", "l1", "c"] 
  case q of
    Nothing -> fail "symbol not found"
    Just m -> return m

Примечание. Я изменил сигнатуру типа и две последние строки.(Поскольку я изменил тип getSymbol, вам придется использовать результат по-разному, где бы вы его ни называли.)

Частичное объяснение:

Вы используете синтаксис do,что приводит к монадическому значению.Тип возврата getSymbol был String, что совпадает с [Char].Списки - это монады, так что это нормально.

Но затем вы вызываете getQuote справа от <-, что приводит к значению IO.IO является монадическим, но IO - это не то же самое, что списки, поэтому мы имеем ошибку.(Вы должны использовать ту же монаду в правой части <-, что и для блока do.)

Редактировать: Вышеуказанное изменение кода не происходитбыть достаточно.m имеет тип Map (QuoteSymbol, QuoteField) QuoteValue, который явно не совпадает с String, поэтому вы хотите вычислить что-то из m, а не возвращать его напрямую.Я не знаю точно, что вы хотите здесь сделать.

Кроме того, вы используете getSymbol в вашем варианте кода синтаксического анализа.Лучше, если вы сохраните input в getSymbol в вашем Options и вызовете getSymbol позже с этим значением, после того как вы обработали параметры командной строки.(В противном случае вы можете связаться с серверами Yahoo только для того, чтобы обнаружить, что другой параметр командной строки неверен, и выбросить ответ. Не говоря уже о том, что поле optSymbol не может содержать IO.)

...