Kernighan& Ritchie字计数程序在功能语言 [英] Kernighan & Ritchie word count example program in a functional language

查看:91
本文介绍了Kernighan& Ritchie字计数程序在功能语言的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在网上阅读一些关于函数式编程的知识,我想我对它的概念有一个基本的概念。



我很好奇如何在一个纯函数编程语言中解决涉及某种状态的日常编程问题。



例如:语言是以纯函数式语言实现的?



只要解决方案是纯函数式,任何贡献都是受欢迎的。



这本书中的字数C代码:

  #include< stdio.h> 

#define IN 1 / *一个字内* /
#define OUT 0 / *字外* /

/ *计数行,字和输入字符* /
main()
{
int c,nl,nw,nc,state;

state = OUT;
nl = nw = nc = 0;
while((c = getchar())!= EOF){
++ nc;
if(c =='\\\
')
++ nl;
if(c ==''|| c =='\\\
'|| c ='\t')
state = OUT;
else if(state == OUT){
state = IN;
++ nw;
}
}

printf(%d%d%d \\\
,nl,nw,nc);
}


解决方案

您将需要根据当前字符和当前状态来划分从一些状态迁移的纯操作获取数据流的IO操作。



Haskell解决方案从Tikhon是非常干净,但对您的输入数据执行三次传递,将导致整个输入包含在内存中,直到计算结果。您可以逐步处理数据,我在下面使用文本包,但没有其他高级Haskell工具(这可以清除它,以非Haskellers的理解为代价)。



首先我们有序言:

  { - #LANGUAGE BangPatterns# - } 

.Text.Lazy as T
将Data.Text.Lazy.IO导入为TIO

我们定义我们的数据结构来保存进程的状态(字符,单词和行数以及状态IN / OUT):

  data Counts = Cnt {nc,nl,nw ::!Int 
,state :: State}
导出(Eq,Ord,Show)

数据状态= IN | OUT
导出(Eq,Ord,Show)

现在我定义一个零状态只是为了方便使用。我通常会做一些辅助函数或者使用像lense这样的包来增加 Counts 结构中的每个字段,但是不会有这个答案:

  zeros :: Counts 
zeros = Cnt 0 0 0 OUT
pre>

现在我把你的系列if / else语句翻译成一个纯状态机:

  op :: Counts  - > Char  - >计数
op c'\\\
'= c {nc = nc c + 1,nw = nw c + 1,nl = nl c + 1,state = OUT}
op c ch | ch ==''|| ch =='\t'= c {nc = nc c + 1,state = OUT}
|状态c == OUT = c {nc = nc c + 1,nw = nw c + 1,state = IN}
|否则= c {nc = nc c + 1}



函数只是获取输入流并折叠我们对字符的操作:

  main = do 
contents < - TIO.getContents
print $ T.foldl'op zeros contents

编辑:你提到不理解语法。这里是一个更简单的版本,我将解释:

  import Data.Text.Lazy as T 
import Data。 Text.Lazy.IO as TIO

操作(nc,nw,nl,st)ch
| ch =='\\\
'=(nc + 1,nw + 1,nl + 1,True)
| ch ==''|| ch =='\t'=(nc + 1,nw,nl,True)
| st =(nc + 1,nw + 1,nl,False)
|否则=(nc + 1,nw,nl,st)

main = do
contents< - TIO.getContents
print $ T.foldl'op ,0,True)contents




  • import 语句让我们访问我们使用的 getContents foldl'函数。


  • op 函数使用一堆警卫 - 例如 |


  • 元组<$

    c $ c>(...,...,...,...)
    包含我们的所有状态。 Haskell变量是不可变的,因此我们通过向前面的变量的值添加一个(或不是)来创建新的元组。



I have been reading a little bit about functional programming on the web lately and I think I got a basic idea about the concepts behind it.

I'm curious how everyday programming problems which involve some kind of state are solved in a pure functional programing language.

For example: how would the word count program from the book 'The C programming Language' be implemented in a pure functional language?

Any contributions are welcome as long as the solution is in a pure functional style.

Here's the word count C code from the book:

#include <stdio.h>

#define IN  1 /* inside a word */
#define OUT 0 /* outside a word */

/* count lines, words, and characters in input */
main()
{
  int c, nl, nw, nc, state;

  state = OUT;
  nl = nw = nc = 0;
  while ((c = getchar()) != EOF) {
    ++nc;
    if (c == '\n')
      ++nl;
    if (c == ' ' || c == '\n' || c = '\t')
      state = OUT;
    else if (state == OUT) {
      state = IN;
      ++nw;
    }
  }

  printf("%d %d %d\n", nl, nw, nc);
}

解决方案

Basically, in a functional styly you'll want to divide the IO operation of getting your stream of data from the pure operation of some stateful transistion based on the current character and the current state.

The Haskell solution from Tikhon is very clean but performs three passes on your input data and will result in the entire input being contained in memory until the result is computed. You can process data incrementally, which I do below using the Text package but no other advanced Haskell tools (which could clean this up at the expense of understandability by non-Haskellers).

First we have our preamble:

{-# LANGUAGE BangPatterns #-}

import Data.Text.Lazy as T
import Data.Text.Lazy.IO as TIO

Then we define our data structure to hold the state of the process (number of characters, words, and lines along with the State IN/OUT):

data Counts = Cnt { nc, nl, nw :: !Int
                  , state :: State  }
        deriving (Eq, Ord, Show)

data State = IN | OUT
        deriving (Eq, Ord, Show)

Now I define a "zero" state just for easy use. I'd normally make a number of helper functions or use a package like lense to make incrementing each field in the Counts structure simple, but will go without for this answer:

zeros :: Counts
zeros = Cnt 0 0 0 OUT

And now I translate your series of if/else statements into a pure state machine:

op :: Counts -> Char -> Counts
op c '\n' = c { nc = nc c + 1, nw = nw c + 1, nl = nl c + 1, state=OUT }
op c ch | ch == ' ' || ch == '\t' = c { nc = nc c + 1, state=OUT }
        | state c == OUT = c { nc = nc c + 1, nw = nw c + 1, state = IN }
        | otherwise  = c { nc = nc c + 1 }

Finally the main function just gets the input stream and folds our operation over the characters:

main = do
        contents <- TIO.getContents
        print $ T.foldl' op zeros contents

EDIT: You mentioned not understanding the syntax. Here is an even simpler version that I will explain:

import Data.Text.Lazy as T
import Data.Text.Lazy.IO as TIO

op (nc, nw, nl, st) ch
  | ch == '\n'              = (nc + 1, nw + 1 , nl + 1, True)
  | ch == ' ' || ch == '\t' = (nc + 1, nw     , nl    , True)
  | st                      = (nc + 1, nw + 1 , nl    , False)
  | otherwise               = (nc + 1, nw     , nl    , st)

main = do
        contents <- TIO.getContents
        print $ T.foldl' op (0,0,0,True) contents

  • The import statements give us access to the getContents and foldl' functions we use.

  • The op function uses a bunch of guards - parts like | ch = '\n' - which is basically like a C if/elseif/else series.

  • The tuples ( ... , ... , ... , ... ) contain all our state. Haskell variables are immutable, so we make new tuples by adding one (or not) to the values of the previous variables.

这篇关于Kernighan&amp; Ritchie字计数程序在功能语言的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆