我認為在 JavaScriptjoin中Control.Monad具有相同的功能。Array.flat
https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
但是,這出乎我的意料,實際行為是
f :: Maybe a -> Maybe a
f = \a -> join (Just a) -- works as I expected
f' :: a -> Maybe a
f' = \a -> join (Just a) -- I thought it returns Maybe a
-- Occurs check: cannot construct the infinite type: a ~ Maybe a
-- Expected type: Maybe (Maybe a)
-- Actual type: Maybe a
是否有可用的扁平化功能或任何解決方法?
uj5u.com熱心網友回復:
join總是將兩層壓平為一層。理想情況下,我們想表達類似“遞回展平任何嵌套層;如果我們只有一層,不要做任何事情”。這將需要一個型別
type family Flattened x where
Flattened (m (m a)) = Flattened (m a)
Flattened (m a) = m a
flatten :: x -> Flattened x
實際上,這不能(AFAIK)這樣實作,我們需要一些重型機械:
{-# LANGUAGE TypeFamilies, GADTs, ConstraintKinds
, MultiParamTypeClasses, FlexibleInstances
, RankNTypes, UnicodeSyntax
, ScopedTypeVariables, AllowAmbiguousTypes, TypeApplications #-}
import Control.Monad
type family Stripped m x where
Stripped m (m a) = Stripped m a
Stripped m x = x
type Bare m x = Stripped m x ~ x
data DepthSing m x where
BareSing :: Bare m x => DepthSing m x
DeepSing :: KnownDepth m x => DepthSing m (m x)
class KnownDepth m x where
depth :: DepthSing m x
flatten :: ? m x . (Monad m, KnownDepth m x) => m x -> m (Stripped m x)
flatten p = case depth @m @x of
BareSing -> p
DeepSing -> flatten $ join p
instance KnownDepth m Char where
depth = BareSing
instance KnownDepth m a => KnownDepth m (m a) where
depth = DeepSing
現在
*Main> flatten (Just (Just 'v'))
Just 'v'
*Main> flatten (Just (Just (Just 'w')))
Just 'w'
*Main> flatten (Just 'i')
Just 'i'
尷尬的是,我們需要KnownDepth為每個“原始”型別提供一個專用實體。
instance KnownDepth m Int where depth = BareSing
instance KnownDepth m Bool where depth = BareSing
...
也許-XIncoherentInstances可以提供幫助,但這是我沒有觸及的擴展。
更糟糕的問題是,這不適用于展平例如Maybe (Maybe [Int])to Maybe [Int],我們需要二次方許多實體:
instance KnownDepth Maybe [x] where depth = BareSing
instance KnownDepth Maybe (Either c x) where depth = BareSing
...
instance KnownDepth [] (Maybe x) where depth = BareSing
instance KnownDepth [] (Either c x) where depth = BareSing
...
instance KnownDepth (Either c) [x] where depth = BareSing
instance KnownDepth (Either c) (Maybe x) where depth = BareSing
...
...
如果你也想要這種行為'w' -> Just 'w',這可以通過
flatten' :: ? m x . (Monad m, KnownDepth m x) => x -> m (Stripped m x)
flatten' p = case depth @m @x of
BareSing -> return p
DeepSing -> flatten p
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/432685.html
標籤:哈斯克尔
