2013-05-09 3 views
1

, что проблема со следующим кодом:Haskell IO тип функции рассогласования

nextMatch :: (a -> Bool) -> [IO a] -> (IO a, [IO a]) 
nextMatch f (x:xs) = do 
    s <- x 
    if f s then (return x, xs) 
     else nextMatch f xs 

Ошибка компиляции говорит:

src\Main.hs:364:10: 
    Couldn't match expected type `(IO a, t0)' with actual type `IO a' 
    In a stmt of a 'do' block: s <- x 
    In the expression: 
     do { s <- x; 
      if f s then (return x, xs) else nextMatch f xs } 
    In an equation for `nextMatch': 
     nextMatch f (x : xs) 
      = do { s <- x; 
       if f s then (return x, xs) else nextMatch f xs } 

Я хочу функцию, которая ищет список на матч и возвращает согласованный элемент плюс оставшийся список, как кортеж.

Я еще совсем новичок в Haskell, так что эта проблема может быть что-то очень простое ...

Спасибо! Chris

+4

Замечание общего порядка. Монадические аргументы (такие как 'IO [a]' или ваш '[IO a]') - это почти всегда плохая идея. Непристойный код обычно принимает чистые аргументы, используя do-notation или '>> =', чтобы применить их к монадическим значениям. – isturdy

ответ

1

Как x, если от типа IO a, не нужно повторно его возвращать, в отличие от кортежа, который определенно необходимо вводить в монаду.

if f s then return $ (x, xs) 

Но это не единственная проблема, как ваш находятся в IO монады и ваша подпись не отражает его, как вы вернуть тип (IO a, [IO a]) он должен быть IO (IO a, [IO a]). Тогда ваш код должен быть следующим.

nextMatch :: (a -> Bool) -> [IO a] -> IO (IO a, [IO a]) 
nextMatch f (x:xs) = 
    do 
    done <- fmap f x 
    if done 
    then return $ (x, xs) 
    else nextMatch f xs 

В любом случае, я не знаю, что вы пытаетесь сделать, но подпись вашей функции выглядит довольно неудобно. Он должен выглядеть намного больше как nextMatch :: (a -> Bool) -> [a] -> (a, [a]), а затем использовать return достаточно, чтобы построить его монадическую версию. nextMatchIO = return $ nextMatch, а затем подключите это вычисление к потоку управления, используя другие функции, предоставляемые Control.Monad.

+0

Вам не нужно '' 'в любой из этих версий ... –

+0

Вы правы, но чтобы избежать дополнительных вычислений, которые болезненны для моего мозга, я принял что большую часть времени я буду использовать 'return $ expr' вместо' return expr'. Конечно, это правило не применяется, когда я должен написать профессиональный код, тогда я трачу время, чтобы задать мне вопрос, нужно ли мне использовать '$' или нет. В любом случае, спасибо за ваши замечания. – zurgl

+0

@zurgl Недавно я пришел к выводу, что мне нужно использовать '$' much * less * в монадическом коде. Это становится болезненным, чтобы перемещать вещи вокруг с использованием '>> =' или аппликативного стиля, потому что я продолжаю спотыкаться, думая, что я могу преобразовать 'a <- g $ b; f a 'to' g $ b >> = f', или 'f <$> g $ b'. – Ben

-1

Ваша функция должна возвращать кортеж. Если мой Haskell все еще до уровня, я бы поставил парсы вокруг вашей возвращаемой функции ", если f s тогда (return (x, xs))".

+1

Ваш Haskell еще не «до пар» :) – is7s

9

Здесь не нужно иметь дело с IO. Это, как я бы реализовать его в качестве чистой функции (я добавил Maybe типа, так как не может быть следующий матч):

nextMatch :: (a -> Bool) -> [a] -> Maybe (a, [a]) 
nextMatch _ []  = Nothing 
nextMatch f (x:xs) = if f x then Just (x, xs) else nextMatch f xs 

Как новичок, если вы принимаете что-то с IO в качестве входных данных к функции, или если вы возвращаете структуру данных с IO внутри нее, скорее всего, вы, вероятно, делаете что-то неправильно (вероятно, в коде, на который вы хотите называть это).

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