Если бы это должно проанализировать командные строки, я предложил бы использовать палата общин Cli .
библиотека Apache Commons CLI обеспечивает API для обработки интерфейсов командной строки.
return
: Prelude> :t return
return :: (Monad m) => a -> m a
Итак, return
принимает аргумент типа ] a
и возвращает что-то типа ma
. В этом случае m
равно LeafConType
, поэтому возвращается LeafConType a
.
Теперь предположим, что мы передаем True
. Тогда a = Bool
, поэтому тип возврата должен быть LeafConType Bool
. Однако вы определяете:
return = LeafCon
Итак, return True
становится LeafCon True
. Но это недопустимо, поскольку в определении типа LeafConType
указано, что
data LeafConType a = LeafCon (a, Int, Int)
So для LeafConType Bool
аргумент LeafCon
должен иметь тип ( Bool, Int, Int)
, не только Bool
. И вот что означает ошибка компиляции: a
не может быть таким же, как (a, Int, Int)
. Вы заявляете:
Я хочу провести вычисления, пока
i
ниже, чемn
.
Это означает, что вам потребуются некоторые значения по умолчанию для i
и n
, поскольку в противном случае невозможно будет определить return
. Если оба они по умолчанию равны нулю, вы можете определить:
return a = LeafCon (a, 0, 0)
(>> =)
: Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
Теперь посмотрите на свою реализацию (немного другая запись, та же идея):
lc@(LeafCon (t, i, n)) >>= f | i >= n = lc
| otherwise = f t
Здесь мы видим, что lc
возвращается, когда i> = n
. Но lc
имеет тип LeafConType a
, а f
- это функция, которая может возвращать значение типа LeafConType b
, для любое b
. В результате может оказаться, что b
не равно a
, и, следовательно, эти типы не совпадают. В заключение вы серьезно должны задать себе один вопрос:
Можно ли все равно выразить этот тип вычислений в виде монады?
Функции, которые вы указали для >> =
и return
не удовлетворяют типы, требуемые Monad
:
return :: a -> LeafConType a
Учитывая объявление
return = LeafCon
, вы присваиваете функции несовместимый тип
return :: (a, Int, Int) -> LeafConType a
Оператор типа return 42
поэтому было бы невозможно в вашей монаде.
Я вообще не понимаю, что ваша монада должна делать. Сначала взгляните на простые рабочие монады!
instance Monad [] where
(>>=) = concatMap
return a = [a]
instance Monad Maybe where
return = Just
(Just x) >>= f = f x
Nothing >>= f = Nothing
Судя по вашему описанию того, что вы хотите, чтобы ваша монада делала, я думаю, вам нужно что-то вроде этого:
data LeafConType a = LeafCon { runLeafCon' :: Int -> Int -> (Maybe a, Int, Int) }
runLeafCon :: Int -> Int -> LeafConType a -> Maybe a
runLeafCon i n lc = let (t, _, _) = runLeafCon' lc i n in t
getI :: LeafConType Int
getI = LeafCon $ \i n -> (Just i, i, n)
getN :: LeafConType Int
getN = LeafCon $ \i n -> (Just n, i, n)
setI :: Int -> LeafConType ()
setI i = LeafCon $ \_ n -> (Just (), i, n)
setN :: Int -> LeafConType ()
setN n = LeafCon $ \i _ -> (Just (), i, n)
instance Monad LeafConType where
return t = LeafCon $ \i n -> if (i < n)
then (Just t, i, n)
else (Nothing, i, n)
(LeafCon k) >>= f =
LeafCon $ \i n ->
let (t, i', n') = k i n
in case t of
Nothing -> (Nothing, i', n')
(Just t') -> if (i' < n')
then runLeafCon' (f t') i' n'
else (Nothing, i, n)
example :: Int -> LeafConType ((), Int)
example x = do
i <- getI
m <- setI (i + x)
return (m, i + x)
Некоторые примеры:
*Main> runLeafCon 2 10 $ example 4
Just ((),6)
*Main> runLeafCon 2 10 $ example 8
Nothing
*Main> runLeafCon 2 10 $ example 7
Just ((),9)
Я довольно быстро собрал это вместе, это довольно уродливо, и я не проверял, подчиняется ли он какому-либо закону Монад, так что используйте на свой страх и риск! :)