извлечение имен из списка пар (имя, обработчик)

Вот простой пример использования haskeline с преобразователем StateT для создания цикла команд ввода с отслеживанием состояния:

{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts #-}

import Control.Monad.State.Strict
import Control.Monad.Trans (lift)
import System.Console.Haskeline

main =  runStateT (runInputT defaultSettings loop) ""

check ma b fb = maybe b fb ma

commands :: (MonadState String m, MonadIO m) => [(String, [String] -> InputT m ())]
commands = [ ("set", performSet), ("get", performGet) ]

performSet args = lift $ put (head args)
performGet _ = do v <- lift get; outputStrLn $ "v = " ++ show v

loop :: (MonadException m, MonadState String m) => InputT m ()
loop = do
   minput <- getInputLine "% "
   check minput (return ()) $ \inp -> do
     let args = words inp
     case args of
       [] -> loop
       (arg0:argv) -> do
         case lookup arg0 commands of
           Nothing      -> do outputStrLn "huh?"; loop
           Just handler -> do handler argv; loop

Список commands содержит все распознанные команды - пары (имя, обработчик). Я хочу получить список имен, используя выражение вроде:

commandNames = map fst commands

но средство проверки типов жалуется на «Нет экземпляра для (MonadState String m0) из-за использования« команд »- переменная типа« m0 »неоднозначна ...»

Что мне нужно сделать, чтобы удовлетворить проверку типов?


person ErikR    schedule 08.12.2014    source источник


Ответы (1)


commands является полиморфным, у него есть переменная типа, m, но commandNames :: [String] не имеет переменных типа. Это означает, что (за исключением некоторых встроенных значений по умолчанию) вывод типа не сможет вывести переменную типа для commands. Есть две вещи, которые вы можете сделать. Вы можете указать тип для commands самостоятельно

commandNames :: [String]
commandNames = map fst (commands :: [(String, [String] -> InputT (StateT String IO) ())])

Или вы можете изменить свой код так, чтобы значение с большим количеством переменных типа определялось с точки зрения того, с меньшим количеством переменных.

commandNames :: [String]
commandNames = ["set", "get"]

commands :: (MonadState String m, MonadIO m) => [(String, [String] -> InputT m ())]
commands = zip commandNames [performSet, performGet]
person Cirdec    schedule 08.12.2014