Я пытаюсь создать стек монадных трансформаторов, и у меня возникают проблемы с получением правильных сигнатур типов для моих функций. (Я все еще довольно новичок в Haskell)Haskell Monad Transformer Stack and Type Signatures
Стек объединяет несколько трансформаторов StateT, поскольку у меня есть несколько состояний, которые мне нужно отслеживать (два из которых могут быть скопированы, но я доберусь до этого в секунду) и WriterT для ведения журнала.
Вот что я до сих пор:
module Pass1 where
import Control.Monad.Identity
import Control.Monad.State
import Control.Monad.Writer
import Data.Maybe
import qualified Data.Map as Map
import Types
data Msg = Error String
| Warning String
type Pass1 a = WriterT [Msg] (StateT Int (StateT [Line] (StateT [Address] Identity))) a
runPass1 addrs instrs msgs = runIdentity (runStateT (runStateT (runStateT (runWriterT msgs) 1) instrs) addrs)
--popLine :: (MonadState s m) => m (Maybe s)
--popLine :: (Monad m) => StateT [Line] m (Maybe Line)
popLine :: (MonadState s m) => m (Maybe Line)
popLine = do
ls <- get
case ls of
x:xs -> do
put xs
return $ Just x
[] -> return Nothing
incLineNum :: (Num s, MonadState s m) => m()
incLineNum = do
ln <- get
put $ ln + 1
curLineNum :: (MonadState s m) => m s
curLineNum = do
ln <- get
return ln
evalr = do l <- popLine
--incLineNum
return l
Я хотел бы popLine
возиться с [Line]
состояния и xLineNum
функции влияют на Int
состояние. evalr
- это расчет, который будет передан в runPass1
.
Всякий раз, когда я загрузить код я бегу на ошибки, которые, как правило, из следующих различных:
Pass1.hs:23:14:
No instance for (MonadState [t] m)
arising from a use of `get' at Pass1.hs:23:14-16
Possible fix: add an instance declaration for (MonadState [t] m)
In a stmt of a 'do' expression: ls <- get
In the expression:
do ls <- get
case ls of {
x : xs -> do ...
[] -> return Nothing }
In the definition of `popLine':
popLine = do ls <- get
case ls of {
x : xs -> ...
[] -> return Nothing }
Pass1.hs:22:0:
Couldn't match expected type `s' against inferred type `[Line]'
`s' is a rigid type variable bound by
the type signature for `popLine' at Pass1.hs:21:23
When using functional dependencies to combine
MonadState [Line] m,
arising from a use of `get' at Pass1.hs:23:14-16
MonadState s m,
arising from the type signature for `popLine'
at Pass1.hs:(22,0)-(28,31)
When generalising the type(s) for `popLine'
Pass1.hs:23:14:
Could not deduce (MonadState [Line] m)
from the context (MonadState s m)
arising from a use of `get' at Pass1.hs:23:14-16
Possible fix:
add (MonadState [Line] m) to the context of
the type signature for `popLine'
or add an instance declaration for (MonadState [Line] m)
In a stmt of a 'do' expression: ls <- get
In the expression:
do ls <- get
case ls of {
x : xs -> do ...
[] -> return Nothing }
In the definition of `popLine':
popLine = do ls <- get
case ls of {
x : xs -> ...
[] -> return Nothing }
Ни одна из подписей не кажутся правильными, но POPLINE это первая функция, так что это только один, который сразу вызывает ошибку.
Стараюсь добавив, что он предлагает в сигнатуре типа (например: popLine :: (MonadState [Line] m) => ...
, но тогда ошибки вроде так:
Pass1.hs:21:0:
Non type-variable argument in the constraint: MonadState [Line] m
(Use -XFlexibleContexts to permit this)
In the type signature for `popLine':
popLine :: (MonadState [Line] m) => m (Maybe Line)
Я всегда кажется, чтобы получить это сообщение всякий раз, когда я пытаюсь сделать что-то, что не является типа, похоже, (MonadState s m)
ok и ошибка на чем-то другом, но когда я пытаюсь использовать его с [a]
вместо s
, это ошибки, подобные приведенному выше. (Первоначально [Line] и Int были загружены в одном состоянии, но я получал эту ошибку, поэтому я подумал, что попытаюсь поместить их в отдельные состояния).
GHC 6.10.4, Kubuntu
Итак, может ли кто-нибудь рассказать мне, что происходит, и дать объяснение/показать мне правильные подписи типов, или кто-нибудь знает хорошую ссылку на этот материал (единственное, что имеет помогли до сих пор «Monad Transformers Step by Step», но это просто использует одну функцию состояния aux и одно StateT)?
Большое спасибо заранее.
Редактировать
Вот компиляции кода включения JFT и предложения Эдварда:
{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- needed for: deriving (Functor,Monad)
{-# LANGUAGE MultiParamTypeClasses #-} -- needed for: MonadState instance
{-# LANGUAGE FlexibleContexts #-} -- needed for: (MonadState PassState m) => ...
module Pass1 where
import Control.Monad.State
import Control.Monad.Writer
import Data.Maybe
import Types
type Lines = [Line]
type Addresses = [Address]
type LineNum = Int
type Messages = [Msg]
data Msg = Error String
| Warning String
data PassState = PassState { passLineNum :: LineNum
, passLines :: Lines
, passAddresses :: Addresses
}
newtype Pass1 a = Pass1 { unPass1 :: WriterT Messages (State PassState) a
}
deriving (Functor,Monad)
instance MonadState PassState Pass1 where
get = Pass1 . lift $ get
put s = Pass1 . lift $ put s
runPass1 :: PassState -> Pass1 a -> ((a, Messages), PassState)
runPass1 state = flip runState state .
runWriterT .
unPass1
curLineNum :: (MonadState PassState m) => m LineNum
curLineNum = do
state <- get
return $ passLineNum state
nextLine :: (MonadState PassState m) => m (Maybe Line)
nextLine = do
state <- get
let c = passLineNum state
let l = passLines state
case l of
x:xs -> do
put state { passLines = xs, passLineNum = (c+1) }
return $ Just x
_ -> return Nothing
evalr :: Pass1 (Maybe Line,LineNum)
evalr = do
l <- nextLine
c <- curLineNum
--tell $ Warning "hello"
return (l,c)
I комбинированных incLineNum
и popLine
в nextLine
мне еще нужно, чтобы получить часть Writer монады работать, но думаю, что я знаю, где идти отсюда. Спасибо, парни.
Героизм должен быть вознагражден. +1 –
Удивительный, спасибо ОЧЕНЬ много! Пошаговое объяснение - это то, что мне нужно, спасибо, что нашли время, чтобы сделать это! Ваши предложения по стилю были также оценены. Да, RWH - отличная книга, сейчас у меня есть копия, передо мной. Я думаю, что моя проблема заключается в том, чтобы прочесть ее слишком быстро - это такой красивый язык, я с нетерпением жду его! (кстати, для тех, кто пытается запустить код JFT эти GHC расширения должны быть включены :) {- # LANGUAGE GeneralizedNewtypeDeriving # -} {- # LANGUAGE TypeSynonymInstances # -} {- # LANGUAGE FlexibleContexts # - } {- # LANGUAGE MultiParamTypeClasses # -} – paul
Кроме того, аккуратный трюк, вставляющий ваши комментарии в {- и -}, я должен буду помнить, что при размещении на досках объявлений. Делает копирование кода, чтобы запустить его очень легко. – paul