Есть ли способ обернуть частичное совпадение с образцом в Maybe?
Я хочу написать код вроде этого:
fromMaybe defaultValue $ do
[a, b] <- mkList :: [Int]
[x] <- mkList' a b :: [Int]
return $ x
где значение этого выражения будет defaultValue
, если mkList
оценивается как список с длиной /= 2, или если mkList' a b
оценивается как список с длиной /= 1. В противном случае выражение оценивается как единственный элемент, возвращаемый mkList' a b
.
Я подумал, что монада Maybe
отлично подойдет для этого. Но как я могу превратить неудачное сопоставление с образцом в Nothing
, а успешное совпадение в Just
?
Можно ли добиться этого в Haskell?
Ваш код почти работает как есть. Вам нужно только добавить немного pure
и изменить тип:
import Data.Maybe
f defaultValue mkList mkList' = fromMaybe defaultValue $ do
[a, b] <- pure mkList :: Maybe [Int]
[x] <- pure (mkList' a b) :: Maybe [Int]
return x
Вам даже не нужны эти :: Maybe [Int]
аннотации.
В GHCi вы можете увидеть ожидаемое поведение:
ghci> f 0 [1,2,3] (\x y -> [x,y])
0
ghci> f 0 [1,2] (\x y -> [x])
1
ghci> f 0 [1,2] (\x y -> [y])
2
ghci> f 0 [1,2] (\x y -> [x,y])
0
Механизм, стоящий за этим, объясняет Даниэль Вагнер в комментариях:
do [a, b] <- <X> <Y>
синтаксический сахар для
let ok [a, b] = do <Y> ok _ = fail "..." in <X> >>= ok
(А для «Может быть» определение неудачи —
fail _ = Nothing
.)Смотрите Отчет.
Обратите внимание, что это работает только внутри блоков do
, где монада является экземпляром MonadFail
.
(Just [1,2,3] :: Maybe [Int]) >>= (\[a,b] -> ())
терпит неудачу... Разве [a, b] <- pure mkList :: Maybe [Int]
не должен быть синтаксическим сахаром для этого?
да, но MonadFail
появляется в тех случаях, когда монада реализует этот класс (как это делает Maybe
). Я считаю, что если нет экземпляра, использующего такой «неудачный» шаблон, это будет ошибкой компиляции. См. hackage.haskell.org/package/base-4.17.0.0/docs/…
@BlueNebula Нет, [a, b] <- <X>; <Y>
— это синтаксический сахар для let ok [a, b] = <Y>; ok _ = fail <Z> in <X> >>= ok
. (А для Maybe
определение fail
— это fail _ = Nothing
.) См. Отчет.
Спасибо ребята! Теперь мне ясно, как это работает.
Подождите... КАК это работает? Как выручает
Maybe
>>=
, если сопоставление с образцомJust [1,2,3]
не удается?