您对类型签名中使用的运算符感到困惑。基本上,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 b
and 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
。此产品类型包含应用程序m
和n
. 一旦您了解了 x-in-a-square 类型,您就会了解 x-in-a-circle 运算符。基本上不像(Monoid m) => Applicative ((,) m)
实例,它的第二个参数只有fmap
s 和s ,两个抽象函子的 s 是一个对函子,它的两个参数都是s 和s。这是两者都适用的对。<*>
Prod
fmap
<*>
(m a, n a)
m
n