繁体   English   中英

Haskell - 从输入的单词列表中查找bigrams

[英]Haskell - finding bigrams from an input list of words

我正在关注NLPWP计算语言学网站并尝试创建一个Haskell程序,以便在单词列表中找到搭配(两个单词的最常见分组,如“美国”或“找到”)。 我有以下工作代码来查找bigram频率:

import Data.Map (Map)
import qualified Data.Map as Map

-- | Function for creating a list of bigrams
-- | e.g. [("Colorless", "green"), ("green", "ideas")]
bigram :: [a] -> [[a]]
bigram []  = []
bigram [_] = []
bigram xs = take 2 xs : bigram (tail xs)

-- | Helper for freqList and freqBigram
countElem base alow = case (Map.lookup alow base) of
                       Just v -> Map.insert alow (v + 1) base
                       Nothing -> Map.insert alow 1 base

-- | Maps each word to its frequency.
freqList alow = foldl countElem Map.empty alow

-- | Maps each bigram to its frequency.
freqBigram alow = foldl countElem Map.empty (bigram alow)

我正在尝试编写一个函数,从每个bigram输出一个Map到[bigram of freram] / [(freq word 1)*(freq word 2)]。 您能提供一些如何处理它的建议吗?

以下代码都不起作用,但它给出了我试图做的模糊轮廓。

collocations alow = 
  | let f key = (Map.lookup key freqBi) / ((Map.lookup (first alow) freqs)*(Map.lookup (last alow) freqs))
    in Map.mapWithKey f = freqBi
  where freqs = (freqList alow)
  where freqBi = (freqBigram alow)

我对Haskell很新,所以如果你知道如何修复搭配程序,请告诉我。 风格窍门也很受欢迎。

当我读到它时,你的困惑源于错误的类型,或多或少。 一般建议:在所有顶级函数上使用类型签名,并确保它们是合理的以及您对函数的期望(我甚至在实现函数之前经常这样做)。

我们来看看你的

-- | Function for creating a list of bigrams
-- | e.g. [("Colorless", "green"), ("green", "ideas")]
bigram :: [a] -> [[a]]

如果你输入一个字符串列表,你将获得一个字符串列表列表,所以你的二元组是一个列表。 您可以决定更明确(至少允许字符串而不是某些类型 - 至少为开头)。 所以,实际上我们得到一个单词列表,从中列出一个Bigrams列表:

type Word = String
type Bigram = (Word, Word)
bigram :: [Word] -> [Bigram]

对于实现,您可以尝试使用Data.List中现成的函数,例如zipWith和tail。

现在你的freqList和freqBigram看起来像

freqList :: [Word] -> Map Word Int
freqBigram :: [Word] -> Map Bigram Int

有了这个错误,编译器的消息将更加清晰。 指出它:注意你在查找单词频率时所做的事情。 你正在搜索word1和word2的频率,而bigram是(word1,word2)。

现在你应该能够自己解决这个问题,我想。

除了最终的colloctions函数之外,您的大多数代码看起来colloctions

我不确定为什么在等号后面有一个流浪管。 你不是想写任何一种模式守卫,所以我认为不应该存在。

Map.lookup返回一个Maybe键,因此尝试除法或乘法不起作用。 也许你想要的是某种带有键和映射的函数,如果键不存在则返回相关的计数或零

除此之外,看起来你的工作并不算太远。

首先,我建议你看看这个功能

insertWith :: Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a

也许你会认识到这种模式

f freqs bg = insertWith (+) bg 1 freqs

接下来@MathematicalOrchid已经指出你的解决方案距离正确不太远。

lookup :: Ord k => k -> Map k a -> Maybe a

您已经在countElems函数中处理了这个问题。

我想要注意的是,有一个叫做Applicative简洁抽象,它非常适合像你这样的问题。

首先,你需要import Control.Applicative如果你在7.10之前使用GHC来获得更新的版本它已经触手可及。

那么抽象提供了什么,类似于Functor它为您提供了一种处理“副作用”的方法,在您的情况下,查找失败的可能性导致Nothing

我们有两个由Applicative提供的运算符: pure<*> ,另外因为每个Applicative都需要是一个Functor我们也得到fmap<$> ,后者只是为了方便起见的中缀别名。

那么这如何适用于您的情况?

<*> :: Applicative f => f (a -> b) -> f a -> f b
<$> :: Functor f => a -> b -> f a -> f b

首先你看到那两个看起来很相似,但是<*>稍微不那么熟悉。

现在有一个功能

f :: Int -> Int
f x = x + 3

和x1 :: Maybe Int x1 = Just 4 x2 :: Maybe Int x2 = Nothing

一个不能只是简单地fy因为这将不进行类型检查-但是,这是要记住的第一个想法。 Maybe是一个Functor (它也是一个Applicative - 它更像是M-thing ,但让我们不去那里)。

f <$> x1 = Just 7
f <$> x2 = Nothing

所以你可以想象f正在查找价值并在Just内部进行计算,如果没有价值 - 也就是我们Nothing情况,我们会做每个懒惰学生做的事情 - 懒惰而什么也不做;-)。

现在我们进入下一部分<*>

g1 :: Maybe (Int -> Int)
g1 = Just (x + 3)
g2 :: Maybe (Int -> Int)
g2 = Nothing

仍然g1 x1不起作用,但是

g1 <*> x1 = Just 7
g1 <*> x2 = Nothing
g2 <*> x1 = Nothing -- remember g2 is Nothing
g2 <*> x2 = Nothing

整齐! - 但这仍然是如何解决您的问题的?

'magic'使用两个运算符...用于多参数函数

h :: Int -> Int -> Int
h x y = x + y + 2

和部分函数应用程序,它只是意味着放入一个值,返回一个等待下一个值的函数。

GHCi> :type h 1
h 1 :: Int -> Int

现在奇怪的是,我们可以使用像h这样的函数。

GHCi> :type h1 <$> x1
h1 <$> x1 :: Maybe (Int -> Int)

这很好,因为那时我们可以使用我们的<*>

y1 :: Maybe Int
y1 = Just 7
h1 <$> x1 <*> y1 = Just (4 + 7 + 2)
                 = Just 13

这甚至适用于任意数量的参数

k :: Int -> Int -> Int -> Int -> Int
k x y z w = ...
k <$> x1 <*> y1 <*> z1 <*> w1 = ...

因此,设计一个纯函数,可以使用IntFloatDouble或任何您喜欢的Functor ,然后使用Functor / Applicative抽象来使您的lookup和频率计算相互协作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM