2016-04-27 3 views
3

Возможно ли сделать экземпляр Monad List, который будет работать следующим образом?Список экземпляров monad, добавляющих элементы

foo = do 
    [1] 
    [2] 
    [3] 

main = print foo -- prints [1,2,3] 

Чтобы сделать эту работу, я должен был бы ограничение, что каждый массив имеют тот же тип: [Int].

+0

Есть ли способ изменить тип '(>>)' на 'm a -> m a -> m a'? –

+2

Фактически вы можете добиться этого с помощью '-XRebindableSyntax', но тогда он не будет иметь ничего общего с монадами. @ Карстен, это должен быть ответ! (На самом деле, более точно сказать, что он будет игнорировать как «1», так и «2» - список игл _not_ игнорируется!) – leftaroundabout

+4

@ VladtheImpala Нужно ли это быть монадой списка? Монада-писатель работает так же, как 'foo = do {tell [1]; скажите [2]; tell [3]} ', если вы затем выполнили' execWriter foo', вы получите '[1, 2, 3]' return. – bheklilr

ответ

5

Вы можете получить эффект, который вы хотите с 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. Кроме того, это просто то, чего вы действительно не должны делать.

+0

Делает смысл. Я использовал Writer для этого раньше, я снова использую это. Благодаря! –

Смежные вопросы