2

The Traversable Paper在第 18-19 页给出了一个融合 monoidal 和 monadic 遍历的示例,这听起来很有趣,但我对他们的 LaTex 感到困惑。

cciBody :: Char -> Count a
wciBody :: Char -> (|M| (State Bool) DotInASquare Count) a

惊人的结果是:

(traverse cciBody) xInACircle (traverse wciBody)

是相同的:

traverse (cciBody xInACircle wciBody)

我认为该结果的类型是:

Count XInASquare (|M| (State Bool) DotInASquare Count) [a]

但不是100%肯定。会说 Emoji 的人可以告诉我它在 Haskell 中的外观吗?

更新

我认为 xInACircle 可能是一个中缀sequenceA。类型匹配。(,)或者也许它只是Traversable. <*>尽管结果看起来有点像,但绝对不是,t (x <*> y) = t x <*> t y但他们在论文中没有使用 Wingding <*>

更新 2

xInACircle 的类型是 (Functor m, Functor n) ⇒ (a → mb) → (a → nb) → (a → (m XInASquare n) b)。提醒你什么?不是我。

4

1 回答 1

5

您对类型签名中使用的运算符感到困惑。基本上,Haskell 语法中的相同规则适用于这些:第一优先级是括号,第二优先级是“应用程序”,最后一个优先级是“运算符”。所以就像你可能写的那样:

f 3 + g 4

[在数学术语中,我们将其写为f (3) + g (4)],在 Haskell 中,有一个标志可以启用-XTypeOperators以冒号开头的中缀类型运算符 ( ),这样您就可以编写类似的表达式f :: a :* b -> b :* [a]来代替f :: Star a b -> Star b [a]. 它只是具有至少两个参数的参数类型构造函数的替代语法。(我想既然->已经是一个中缀类型的构造函数,这几乎不是新闻。)我们也可以把它们写成Comp a band Prod a b

向上箭头和向下箭头是在论文中定义为类型类的一部分的函数,但我不喜欢 Haskell 实际接受这些函数所需的所有编译指示,所以我要在这段代码中解释它们。Comp以下是使用andProd代替其运算符的有效 Haskell 文件的所有相关定义:

import Control.Applicative (Applicative, (<$>), (<*>), pure, WrappedMonad(..), Const(..))
import Data.Traversable (traverse)
import Control.Monad.State.Lazy (State, state, runState)
import Data.Char (isSpace)
import Data.Monoid (Monoid(..))

instance Monoid Integer where
    mempty = 0
    mappend = (+)

-- chained functors
newtype Comp m n a = Comp {runComp :: m (n a)}
instance (Functor m, Functor n) => Functor (Comp m n) where
    fmap f = Comp . fmap (fmap f) . runComp
instance (Applicative m, Applicative n) => Applicative (Comp m n) where
    pure = Comp . pure . pure
    Comp mnf <*> Comp mnx = Comp ((<*>) <$> mnf <*> mnx)

-- outer product of functors
data Prod m n a = Prod {pfst :: m a, psnd :: n a}
instance (Functor m, Functor n) => Functor (Prod m n) where
    fmap f (Prod ma na) = Prod (fmap f ma) (fmap f na)
instance (Applicative m, Applicative n) => Applicative (Prod m n) where
    pure x = Prod (pure x) (pure x)
    Prod mf nf <*> Prod mx nx = Prod (mf <*> mx) (nf <*> nx)

-- page 19,20

type Count = Const Integer
count :: a -> Count b
count _ = Const 1

cciBody :: Char -> Count a
cciBody = count

cci :: String -> Count [a]
cci = traverse cciBody

test :: Bool -> Integer
test b = if b then 1 else 0

lciBody :: Char -> Count a
lciBody c = Const (test (c == '\n'))

lci :: String -> Count [a]
lci = traverse lciBody

wciBody :: Char -> Comp (WrappedMonad (State Bool)) Count a
wciBody c = Comp (fmap Const (WrapMonad $ state $ updateState c)) where
    updateState :: Char -> Bool -> (Integer, Bool)
    updateState c w = let s = not (isSpace c) in (test (not w && s), s)

wci :: String -> Comp (WrappedMonad (State Bool)) Count [a]
wci = traverse wciBody

runWci :: String -> Integer
runWci s = fst $ runState (fmap getConst $ unwrapMonad $ runComp $ wci s) False

如果您不清楚任何函数的来源,我已将导入限制在顶部,因此请在此处查找(或使用 Hoogle)查找它们的定义。

您正在调用的运算xInACircle符是一个运算符,它接受一个a -> m b和一个a -> n b并产生一个函数a -> Prod m n b。此产品类型包含应用程序mn. 一旦您了解了 x-in-a-square 类型,您就会了解 x-in-a-circle 运算符。基本上不像(Monoid m) => Applicative ((,) m)实例,它的第二个参数只有fmaps 和s ,两个抽象函子的 s 是一个对函子,它的两个参数都是s 和s。这是两者都适用的对。<*>Prodfmap<*>(m a, n a)mn

于 2014-10-29T21:29:21.317 回答