在文章“ Write you a Haskell”(第34页)中,给出了“一些”和“许多”的以下实现:
从Alternative类型类定义中自动得出的是
many
和some
函数。许多采用单个函数参数,并且 重复应用它直到函数失败,然后产生 到那时为止收集的结果。some
函数的行为类似 如果没有至少一个,它将自身失败 匹配。
-- | One or more.
some :: f a -> f [a]
some v = some_v
where
many_v = some_v <|> pure []
some_v = (:) <$> v <*> many_v
-- | Zero or more.
many :: f a -> f [a]
many v = many_v
where
many_v = some_v <|> pure []
some_v = (:) <$> v <*> many_v
一段时间以来,我一直试图了解这种实现方式。
我不明白如何将“许多”和“一些”应用于“列表”或“也许”
我也不确定(:) <$> v <*> many_v
这是如何得出的?
答案 0 :(得分:0)
在ghc/libraries/base/GHC/Base.hs
中有一个递归声明:
... :: f a -> f [a]
...
many_v = some_v <|> pure []
some_v = liftA2 (:) v many_v -- (:) <$> v <*> many_v
自变量v
必须是以下类型的实例的值:
Alternative
(以及Applicative
和Functor
)。
v
已被解除,只需应用(<*>
)。
该应用程序将产生一个提升的列表。
some
和many
构成v
的构造函数的递归应用程序,
并将构造的值放入列表中。
some
在构建第一个empty
时停止应用程序many
继续进行申请 []
是Alternative
的实例:
instance Alternative [] where
empty = []
(<|>) = (++)
some
尝试使用列表:
av = [[2], [2,3], [], [2,3,5]]
some av -- no error, but never stops
do {v <- some av; return v;} -- no error, but never stops
相比于letter
What are Alternative's "some" and "many" useful for?:
import Control.Monad(Functor(..))
import Control.Applicative
import Data.Char
newtype P a = P { runP :: String -> [(a,String)] }
instance Functor P where
fmap f (P q) = P (\s -> [ (f y,ys) | (y,ys) <- q s])
instance Applicative P where
pure x = P (\s -> [(x,s)])
P p <*> P q = P (\s -> [(x y, ys) | (x,xs) <- p s, (y,ys) <- q xs])
letter = P p where
p (x:xs) | isAlpha x = [(x,xs)]
p _ = []
instance Alternative P where
P p <|> P q = P (\s-> p s ++ q s)
empty = P (\s-> [])
用法:
runP (many letter) "ab123"
letter
是一个聪明的构造函数,
使用局部变量P
使用字段runP
构造一个p
值。
(访问器的结果)runP
是一个函数。
P
是实现Alternative
的类型,也是构造函数。
P
代表解析器。
fmap
未在some
和many
中使用。
<*>
导致函数runP
的应用,
谁的论点还没有在这里。
基本上some
和many
会构造一个程序,该程序会从其参数中获取食物。
参数必须是列表。
由于懒惰,递归在第一个构造函数处停止。
p = some letter -- constructs a program accessed via @runP@
runP p "a1" -- [("a","1")]
q = some [2] -- basically also a program
q -- never stops
递归应用程序不是empty
(列表为[]
),
因为没有标准可以停止,也就是没有输入。
这些站:
some [] -- []
many [] -- [[]]
some Nothing -- Nothing
many Nothing -- Just []
对some
和many
(v
)的参数有更多要求。
v
是作为Alternative
实例的类型的值。v
类型的构造函数的递归应用程序必须以empty
终止。v
必须包含在使用<*>
进行构造时应用的函数,以具有停止条件。结论:
some
和many
无法应用于列表值,
即使列表实现了Alternative
。
为什么列表实现Alternative
?
我认为是在Monoid
顶部添加<|>
接口empty
和Applicative
,
不是因为some
和many
。
foldr (<|>) [] [[2],[],[3,4]] -- [2,3,4]
some
和many
似乎仅用于解析器构造
或更一般而言,使用输入的程序的构造
并产生更多的输出,其中一些可以是empty
。
那已经很普遍了。
但是Alternative
中的位置仅是合理的,
如果大多数Alternative
实例对此有合理的用法。
事实并非如此。