【问题标题】:Haskell - some, many implementationHaskell - 一些,很多实现
【发布时间】:2018-12-13 22:35:22
【问题描述】:

在文章:“Write you a Haskell”(第 34 页)中,给出了“some”和“many”的以下解释:

自动派生自 Alternative 类型类定义是 manysome 函数。 many 接受一个函数参数和 重复应用它直到函数失败,然后产生 收集到那时的结果。 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

我一直在尝试理解这个实现。

我不明白“many”和“some”如何应用于“列表”或“Maybe”。

我也不确定(:) &lt;$&gt; v &lt;*&gt; many_v

这是如何得出的?

【问题讨论】:

  • 我猜这是所有 Haskell 书籍中的锇。
  • 查看stackoverflow.com/questions/18108608/… 及其许多链接。 (可能重复)。 Here's 一个很好的答案。
  • 链接的条目是否回答了我们的问题或者还有什么不清楚的地方?
  • 很清楚,谢谢
  • 对于[]Maybe 这两个函数并不是很有用:但它们对于StateT String [] 这样的类型非常有用

标签: haskell some-and-many alternative-functor


【解决方案1】:

来自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(和ApplicativeFunctor)。 v解除,只需要应用 (&lt;*&gt;)。 应用程序会生成一个提升列表。

somemany 递归应用 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 不用于somemany&lt;*&gt; 导致函数runP 的应用, 谁的论点还没有出现。 基本上somemany 构造了一个程序,它会从它的参数中吃掉。 参数必须是一个列表。 由于惰性,递归在第一个构造函数处停止。

  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 []

somemanyv)的参数有更多要求。

  • vAlternative 的实例类型的值。
  • v 类型的构造函数的递归应用必须以empty 停止。
  • v 必须包含在构造期间应用的函数,&lt;*&gt; 具有停止条件。

结论: somemany 不能应用于列表值, 即使列表实现了Alternative

list为什么要实现Alternative? 我想,就是在Applicative之上加上Monoid接口&lt;|&gt;empty, 不是因为somemany

  foldr (<|>) [] [[2],[],[3,4]] -- [2,3,4]

somemany 似乎只是用于解析器构造 或更一般地,构建消耗输入的程序 并产生更多的输出,其中一些可以是empty。 这已经很笼统了。 但是Alternative中的地方只是有道理的, 如果大多数Alternative 实例都有合理的用法。 事实并非如此。

【讨论】:

  • 顺便说一句some [2] = x where { x = (:) &lt;$&gt; [2] &lt;*&gt; (x &lt;|&gt; pure []) = [ (2:) ] &lt;*&gt; (x &lt;|&gt; pure []) = fmap (2:) (x &lt;|&gt; pure []) = fmap (2:) x &lt;|&gt; pure [2] = map (2:) x ++ [[2]] }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多