Я борюсь с системой типа haskell. В основном то, что я пытаюсь сделать, это определить структуру данных (cf Ast тип данных в образце кода), который представляет собой монаду (это может быть что-то другое). Этот тип параметризуется a, и на нем нет ограничений. Мой вопрос, когда я хочу вникать этот тип, мне может понадобиться некоторые ограничения на параметр типа, например:Ограничение типа Haskell
{-# LANGUAGE GADTs #-}
import Control.Monad
data Ast a where
Bind :: Ast a -> (a -> Ast b) -> Ast b
Return :: a -> Ast a
instance Functor Ast where
fmap = liftM
instance Applicative Ast where
pure = Return
(<*>) = ap
instance Monad Ast where
(>>=) = Bind
instance Show a => Show (Ast a) where
show (Bind x y) = "bind " ++ {- begin error -} show x {- end error -}
show (Return y) = "return " ++ show y
Это дает следующее сообщение об ошибке:
Could not deduce (Show a1) arising from a use of ‘show’
from the context (Show a)
bound by the instance declaration at src/Main.hs:21:10-31
Possible fix:
add (Show a1) to the context of the data constructor ‘Bind’
In the second argument of ‘(++)’, namely ‘show x’
In the expression: "bind " ++ show x
In an equation for ‘show’: show (Bind x y) = "bind " ++ show x
И это имеет смысл, то компилятор не знает, что x является примером Показать. Мой вопрос: могу ли я выразить это ограничение? В идеале я хотел бы иметь ограничение только на моем Show инстанции, но я также пытался добавить Показать ограничение в Аст конструктор:
data Ast a where
Bind :: (Show a, Show b) => Ast a -> (a -> Ast b) -> Ast b
Return :: a -> Ast a
И я получаю эту ошибку:
No instance for (Show a) arising from a use of ‘Bind’
Possible fix:
add (Show a) to the context of
the type signature for (>>=) :: Ast a -> (a -> Ast b) -> Ast b
In the expression: Bind
In an equation for ‘>>=’: (>>=) = Bind
In the instance declaration for ‘Monad Ast’
Я понимаю Показать ограничение должно быть добавлено в монады уровне определения типа в класса.
Любая идея, как это сделать?
Спасибо.
Если вы _really_ хотите сделать монаду с ограничениями, пакет [rmonad] (https://hackage.haskell.org/package/rmonad) может помочь. –