Вы можете получить эффект, который вы хотите с mtl
«s Writer
монады и ничего безумного:
type AutoList a = Writer [a]()
foo :: AutoList Int
foo = do
tell [1]
tell [2]
tell [3]
toList :: AutoList a -> [a]
toList = execWriter
main = print (toList foo)
Однако, вы можете сделать ужасный хак с -XOverloadedLists
сортировать-оф получить его только список литералов. Проблема заключается в том, что вы должны дать тип подписи на каждой строке:
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module AutoList where
import GHC.Exts
import Control.Applicative
import Control.Monad.Writer
newtype AutoListM a r = AutoListM (Writer [a] r) deriving (Functor, Applicative, Monad)
type AutoList a = AutoListM a()
instance IsList (AutoList a) where
type Item (AutoList a) = a
fromList = AutoListM . tell
fromListN n = AutoListM . tell . take n
toList (AutoListM w) = execWriter w
foo :: AutoList Int
foo = do
[1] :: AutoList Int
[2] :: AutoList Int
[3] :: AutoList Int
main = print (toList foo)
Он должен быть монада для делать записи, но без подписей типа он не может понять, что она должна быть r ~()
в AutoListM Int r
. С явными сигнатурами типа он способен все понять, но я сомневаюсь, что это решение, которое вы действительно хотите, и это больше работает, чем просто использовать и tell
. Кроме того, это просто то, чего вы действительно не должны делать.
Есть ли способ изменить тип '(>>)' на 'm a -> m a -> m a'? –
Фактически вы можете добиться этого с помощью '-XRebindableSyntax', но тогда он не будет иметь ничего общего с монадами. @ Карстен, это должен быть ответ! (На самом деле, более точно сказать, что он будет игнорировать как «1», так и «2» - список игл _not_ игнорируется!) – leftaroundabout
@ VladtheImpala Нужно ли это быть монадой списка? Монада-писатель работает так же, как 'foo = do {tell [1]; скажите [2]; tell [3]} ', если вы затем выполнили' execWriter foo', вы получите '[1, 2, 3]' return. – bheklilr