2012-07-11 2 views
2

У меня есть проблемы со встроенной функцией с монадой-спискомКак я могу построить функцию с Monad-List?

> multab 4 
["1*1=1","1*2=2","1*3=3","1*4=4","2*2=4","2*3=6","2*4=8","3*3=9","3*4=12","4*4=16"] 

Так что я хочу, чтобы начать, как:

multab :: Integer -> [String] 

для отдыха, вы хотели бы давать какие-либо предложения?

Заранее спасибо.

+1

Что вы подразумеваете под monad-list? Вы должны использовать control.Monad.List? –

+0

Я не хочу использовать какой-либо конкретный monadList здесь. Просто пытаюсь построить это fucntion с любым monad-List, btw я не уверен, как я могу использовать код с Contol-list! – user1516831

+4

Зачем беспокоиться о монадах? 'mulTab ​​n = [printf"% d *% d =% d "i j (i * j) | i <- [1..n], j <- [1..n]] ' – augustss

ответ

2

Естественный способ сделать это, чтобы создать список всех пар (i, j) с i < или = j, а затем карту (\(i, j) -> show i ++ "*" ++ show j ++ "=" ++ show (i*j)) на нем. Наиболее очевидным способом создания такого списка было бы написать [(i, j) | i <- [1..n], j <- [1..n], i <= j]. Хотя было бы лучше сделать [1..n] >>= list where list i = map (\k -> (i, k)) [i..n], так как это не делает никакой фильтрации (потому что это не создает нежелательные пары).

+0

Спасибо, что было действительно полезно! – user1516831

+0

Фильтрация, как у вас в этом понимании списка, на данный момент не имеет смысла. И решение монады могло, возможно, более понятно, быть написано в блоке 'do'. Однако это немного похоже на вкус. – leftaroundabout

+0

@leftaroundabout, спасибо, исправлено. –

2

Вот несколько проблемных решений, основанных на ответе Каролиса.

> let nonDec xs = and $ zipWith (>=) (drop 1 xs) xs 
nonDec :: Ord b => [b] -> Bool 

> let getSets s n = filter nonDec $ replicateM n s 
getSets :: Ord b => [b] -> Int -> [[b]] 

> getSets [1,2,3,4] 2 
[[1,1],[1,2],[1,3],[1,4],[2,2],[2,3],[2,4],[3,3],[3,4],[4,4]] 

> let showExp = \[i,j] -> show i ++ "*" ++ show j ++ "=" ++ show (i*j) 
showExp :: [Integer] -> [Char] 

> map showExp $ getSets [1,2,3,4] 2 
["1*1=1","1*2=2","1*3=3","1*4=4","2*2=4","2*3=6","2*4=8","3*3=9","3*4=12","4*4=16"] 

Так, multab является \n -> map showExp $ getSets [1..n] 2.

+0

Thnaks так много! – user1516831

8

В основном вы хотите сгенерировать список записей, а затем распечатать их.

Начнем с записей. Они состоят из двух целых чисел и их произведения. Итак, давайте определим синоним типа для хранения двух целых чисел

type Entry = (Integer, Integer) 

и оценочную функцию, которая вычисляет произведение этих чисел,

eval :: Entry -> Integer 
eval = uncurry (*) 

Затем мы определим функцию для генерации записей:

gen :: Integer -> [Entry] 
gen n = [(i, j) | i <- [1 .. n], j <- [i .. n]] 

Например:

> gen 4 
[(1,1),(1,2),(1,3),(1,4),(2,2),(2,3),(2,4),(3,3),(3,4),(4,4)] 

Далее, мы должны быть в состоянии напечатать запись:

showEntry :: Entry -> String 
showEntry [email protected](i, j) = show i ++ "*" ++ show j ++ "=" ++ show (eval e) 

Например:

> showEntry (2, 3) 
"2*3=6" 

Наконец, давайте склеить эти куски вместе:

multab :: Integer -> [String] 
multab = map showEntry . gen 

Здесь мы идем :

> multab 4 
["1*1=1","1*2=2","1*3=3","1*4=4","2*2=4","2*3=6","2*4=8","3*3=9","3*4=12","4*4=16"] 
1

Как альтернатива другому отвечает тот, который использует Список как Монаду.

multab :: Integer -> [String] 
multab n = do 
    i <- [1..n] 
    j <- [i..n] 
    return $ show i ++ "*" ++ show j ++ "=" ++ show (i*j) 

Где первые два правила связывают каждую пару целых чисел (i,j) с j <= i <= n. Последнее правило возвращает напечатанное значение.

Более практичным является, пожалуй, список постижение версия

multab2 :: Integer -> [String] 
multab2 n = 
    [ show i ++ "*" ++ show j ++ "=" ++ show (i*j) 
    | i <- [1..n] 
    , j <- [i..n] ] 

, которые могут быть непосредственно переведены на версию монады как структура предполагает, хотя это не самый эффективный перевод. Кроме того, это эквивалентно тому, что вы получите, когда вы введете все функции из ответа dblhelix.

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