在 Haskell 中映射 `IO (S (Maybe a))`?
mapping `IO (S (Maybe a))` in Haskell?
基于Data.Typeable cast and Maybe pattern match behavior in Haskell
我有
- 一个结构:
data S a = S {val :: IO a}
- 一个结构:
S (Maybe a))
- 一个结构:
IO (S (Maybe a)))
- 一个函数:
Maybe a -> IO (S (Maybe a))
然后,基本上需要一个函数
_map :: (Maybe a -> IO (S (Maybe a))) -> S (Maybe a) -> IO (S (Maybe b))
这个问题的代码非常简单,并且有理由为了我的目的而拥有这样的结构和功能。例如 S {val :: IO a}
实际上持有一个字段值 Data.Vector.Mutable
这就是为什么类型是 IO a
.
基本概念只是 map/function-application 值。
如果 Maybe a
是 Nothing
,我希望代码在 IO
和 return IO (S (Nothing))
.
上不执行任何操作
data S a = S
{ val :: IO a
}
_val :: S (Maybe a) -> IO (Maybe a)
_val = \sMaybeA -> val sMaybeA
_map :: (Maybe a -> IO (S (Maybe b))) -> S (Maybe a) -> IO (S (Maybe b))
_map = \f -> \sMaybeA -> do
val <- sMaybeA |> _val
sMaybeB <- val >>= f
-- Expected type: IO (S (Maybe a))
-- Actual type: Maybe (S (Maybe a))
pure sMaybeB
-- another obvious error because sMaybeB has the error
当然,错误很明显,所以我明白这是怎么发生的,那不是这个问题的范围。
我根本想不通如何用IO
和Maybe
的混合结构来完成预期的类型。你如何解决这个问题?
我不确定你想要达到什么目的。您将 IO
嵌套在另一个 IO
(又名 S
)中的方式有点奇怪。
此外,您的 _map
类型只接受普通居民:
_map :: (Maybe a -> IO (S (Maybe a))) -> S (Maybe a) -> IO (S (Maybe b))
注意最后的 b
。无法从参数中获得这样的 b
,迫使代码始终使用 Nothing :: Maybe b
,并进行适当包装。我想这不是你想要做的。
我把 b
改成了 a
。然后我们可以测试sMaybeA
的结果并据此采取行动。
_map :: (Maybe a -> IO (S (Maybe a))) -> S (Maybe a) -> IO (S (Maybe a))
_map f sMaybeA = do
v <- val sMaybeA
case v of
Nothing -> return (S (return Nothing))
Just _ -> f v
请注意,虽然可以编译,但它可能与您实际需要的有所不同。
我觉得您对 Haskell 类型系统的担忧源于您在此处展示的具有误导性的 API 设计。您正在尝试嵌套您的类型而不是组合它们。我相信,在编写 Haskell 时,您会发现 Haskell 类型之间的组合非常好。您不必退回到幼稚但丑陋的嵌套。
像这样的东西怎么样?
newtype S a = S { val :: IO (Maybe a) }
instance Functor S where
fmap f = S . fmap (fmap f) . val
instance Applicative S where
pure = S . pure . pure
S f <*> S v = S $ liftA2 (<*>) f v
instance Monad S where
S ma >>= f = S $ do
maybex <- ma
case maybex of
Nothing -> pure Nothing
Just a -> val $ f a
weirdMap :: (a -> S b) -> S a -> S b
weirdMap f sa = do
value <- sa
f value
没有嵌套 IO
,因为您 永远不会 需要嵌套 IO
(除非您正在使用 STM
)。您可以简单地组合您的 IO
s,如果其中之一仅用于可变数组并不重要。
我还冒昧地将 Maybe a
嵌入到 S
中,因为您的 API 似乎就是这么做的。然而,你很可能会把它拿出来继续 Functor
/Applicative
/Monad
实例,并继续保持平坦的 IO
层次结构。
基于Data.Typeable cast and Maybe pattern match behavior in Haskell
我有
- 一个结构:
data S a = S {val :: IO a}
- 一个结构:
S (Maybe a))
- 一个结构:
IO (S (Maybe a)))
- 一个函数:
Maybe a -> IO (S (Maybe a))
然后,基本上需要一个函数
_map :: (Maybe a -> IO (S (Maybe a))) -> S (Maybe a) -> IO (S (Maybe b))
这个问题的代码非常简单,并且有理由为了我的目的而拥有这样的结构和功能。例如 S {val :: IO a}
实际上持有一个字段值 Data.Vector.Mutable
这就是为什么类型是 IO a
.
基本概念只是 map/function-application 值。
如果 Maybe a
是 Nothing
,我希望代码在 IO
和 return IO (S (Nothing))
.
data S a = S
{ val :: IO a
}
_val :: S (Maybe a) -> IO (Maybe a)
_val = \sMaybeA -> val sMaybeA
_map :: (Maybe a -> IO (S (Maybe b))) -> S (Maybe a) -> IO (S (Maybe b))
_map = \f -> \sMaybeA -> do
val <- sMaybeA |> _val
sMaybeB <- val >>= f
-- Expected type: IO (S (Maybe a))
-- Actual type: Maybe (S (Maybe a))
pure sMaybeB
-- another obvious error because sMaybeB has the error
当然,错误很明显,所以我明白这是怎么发生的,那不是这个问题的范围。
我根本想不通如何用IO
和Maybe
的混合结构来完成预期的类型。你如何解决这个问题?
我不确定你想要达到什么目的。您将 IO
嵌套在另一个 IO
(又名 S
)中的方式有点奇怪。
此外,您的 _map
类型只接受普通居民:
_map :: (Maybe a -> IO (S (Maybe a))) -> S (Maybe a) -> IO (S (Maybe b))
注意最后的 b
。无法从参数中获得这样的 b
,迫使代码始终使用 Nothing :: Maybe b
,并进行适当包装。我想这不是你想要做的。
我把 b
改成了 a
。然后我们可以测试sMaybeA
的结果并据此采取行动。
_map :: (Maybe a -> IO (S (Maybe a))) -> S (Maybe a) -> IO (S (Maybe a))
_map f sMaybeA = do
v <- val sMaybeA
case v of
Nothing -> return (S (return Nothing))
Just _ -> f v
请注意,虽然可以编译,但它可能与您实际需要的有所不同。
我觉得您对 Haskell 类型系统的担忧源于您在此处展示的具有误导性的 API 设计。您正在尝试嵌套您的类型而不是组合它们。我相信,在编写 Haskell 时,您会发现 Haskell 类型之间的组合非常好。您不必退回到幼稚但丑陋的嵌套。
像这样的东西怎么样?
newtype S a = S { val :: IO (Maybe a) }
instance Functor S where
fmap f = S . fmap (fmap f) . val
instance Applicative S where
pure = S . pure . pure
S f <*> S v = S $ liftA2 (<*>) f v
instance Monad S where
S ma >>= f = S $ do
maybex <- ma
case maybex of
Nothing -> pure Nothing
Just a -> val $ f a
weirdMap :: (a -> S b) -> S a -> S b
weirdMap f sa = do
value <- sa
f value
没有嵌套 IO
,因为您 永远不会 需要嵌套 IO
(除非您正在使用 STM
)。您可以简单地组合您的 IO
s,如果其中之一仅用于可变数组并不重要。
我还冒昧地将 Maybe a
嵌入到 S
中,因为您的 API 似乎就是这么做的。然而,你很可能会把它拿出来继续 Functor
/Applicative
/Monad
实例,并继续保持平坦的 IO
层次结构。