or1ko's diary

日々を書きます

10

言語処理100本ノック 2015

2章はUnixのコマンドの練習のようだけれども、
Haskellを書きたいので、同様のプログラムも作成していく。と思っていたら、よく読んでみたら、プログラム書く演習だった。

10. 行数のカウント
行数をカウントせよ.確認にはwcコマンドを用いよ.

10.hs

import System.Environment
import qualified System.IO.UTF8 as I8

main = do
  file <- getArgs
  body <- I8.readFile $ head file
  print $ length $ lines body
>wc -l hightemp.txt
     24 hightemp.txt
>runghc 10.hs hightemp.txt
24

utf8-string-0.3.8使用。バージョン1では、System.IO.UTF8をGHCで対応したから削除したとのことだったが、つかっているghcHaskell Platform 2014を使っているため。

09

言語処理100本ノック 2015

09. Typoglycemia
スペースで区切られた単語列に対して,各単語の先頭と末尾の文字は残し,それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ.ただし,長さが4以下の単語は並び替えないこととする.適当な英語の文(例えば"I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind .")を与え,その実行結果を確認せよ.

09.hs

import System.Random
import Data.List

main = do
  gen <- getStdGen
  print $ unwords $ map typoglycemia $ zip (words s) (randoms gen :: [Int])
    where 
      s = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."

typoglycemia (s, hint) 
    | length s <= 4 = s
    | otherwise     = [head s] ++ shuffle hint (init $ tail s) ++ [last s]

-- hint は文字列をシャフルする際に使う数値
shuffle hint s = tmp !! (mod hint (length tmp))
              where
                 tmp = permutations s
> runghc 09.hs
"I cun'oldt bevilee that I could autlclay udanrestnd what I was randeig : the paomehnnel peowr of the haumn mind ."
> runghc 09.hs
"I could'nt bieelve that I colud aclltuay ueandsntrd what I was reandig : the paemnhonel poewr of the hamun mind ."
> runghc 09.hs
"I c'dlunot beileve that I cluod alucltay unednrstad what I was rdianeg : the panhonemel poewr of the hmuan mind ."

shuffleが難しかった。
typoglycemia関数をString -> IO String型にするバージョンも作成してみた。

import Control.Monad
import System.Random
import Data.List

main = do
  typoglycemias <- mapM typoglycemia $ words s
  putStrLn $ unwords typoglycemias
   where 
     s = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."

typoglycemia s 
    | length s <= 4 = return s
    | otherwise     = do
       body <- shuffle (init $ tail s) 
       return ([head s] ++ body ++ [last s])

shuffle s = 
  do 
    g <- getStdGen
    return $ tmp !! (mod (fst $ next g) (length tmp))
      where
        tmp = permutations s 

08

言語処理100本ノック 2015

08. 暗号文
与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.

英小文字ならば(219 - 文字コード)の文字に置換
その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ.

import Data.Char

main = putStrLn $ cipher $ cipher s
  where
    s = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

cipher s =  map f s
  where
   f c | isLower c = chr (219 - ord c)
       | otherwise = c

逆関数が必要かと思ったけど、不要だった。
こういう関数を対合というらしい。

対合 - Wikipedia

07

言語処理100本ノック 2015

07. テンプレートによる文生成
引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y="気温", z=22.4として,実行結果を確認せよ.

07.hs

import Text.Printf

main = putStrLn $ f 12 "気温" 22.4

f x y z = printf "%s時の%sは%s" (show x) y (show z)
> runghc .\07.hs
12時の気温は22.4

04-06

言語処理100本ノック 2015

04. 元素記号
"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

04.hs

import qualified Data.Map as M

main = print $ M.fromList $ zip (map f $ zip (words s) [1..]) [1..]
  where 
    s = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

f (s,n)  
  | elem n ns = take 1 s 
  | otherwise = take 2 s
    where
    ns =  [1, 5, 6, 7, 8, 9, 15, 16, 19]
> runghc 04.hs
fromList [("Al",13),("Ar",18),("B",5),("Be",4),("C",6),("Ca",20),("Cl",17),("F",9),("H",1),("He",2),("K",19),("Li",3),("
Mi",12),("N",7),("Na",11),("Ne",10),("O",8),("P",15),("S",16),("Si",14)]

ghciで簡単に書く方法を思いつかなかったのでファイルにした。
辞書は久しぶりに使った。

05. n-gram
与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,"I am an NLPer"という文から単語bi-gram,文字bi-gramを得よ.

Prelude> import Data.List
Prelude Data.List> let f s = filter (\x -> length x == 2) $ subsequences s
Prelude Data.List> f $ words "I am an NLPer"
[["I","am"],["I","an"],["am","an"],["I","NLPer"],["am","NLPer"],["an","NLPer"]]
Prelude Data.List> f $ "I am an NLPer"
["I ","Ia"," a","Im"," m","am","I ","  ","a ","m ","Ia"," a","aa","ma"," a","In"," n","an","mn"," n","an","I ","  ","a "
,"m ","  ","a ","n ","IN"," N","aN","mN"," N","aN","nN"," N","IL"," L","aL","mL"," L","aL","nL"," L","NL","IP"," P","aP"
,"mP"," P","aP","nP"," P","NP","LP","Ie"," e","ae","me"," e","ae","ne"," e","Ne","Le","Pe","Ir"," r","ar","mr"," r","ar"
,"nr"," r","Nr","Lr","Pr","er"]
Prelude Data.List>

06. 集合
"paraparaparadise"と"paragraph"に含まれる文字bi-gramの集合を,それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ.さらに,'se'というbi-gramがXおよびYに含まれるかどうかを調べよ.

06.hs

import Data.List

main = do 
  print $ union x y
  print $ intersect x y
  print $ x \\ y
    where
      x = nub $ bigram "paraparaparadise"
      y = nub $ bigram "paragraph"

bigram = filter (\x -> length x == 2 ) . subsequences
> runghc 06.hs
["pa","pr","ar","aa","ra","pp","ap","rp","rr","pd","ad","rd","pi","ai","ri","di","ps","as","rs","ds","is","pe","ae","re"
,"de","ie","se","pg","ag","rg","gr","ga","gp","ph","ah","rh","gh"]
["pa","pr","ar","aa","ra","pp","ap","rp","rr"]
["pd","ad","rd","pi","ai","ri","di","ps","as","rs","ds","is","pe","ae","re","de","ie","se"]

01-03

言語処理100本ノック 2015

Haskellで何か書きたくなったので、上記のサイトの問題を解いていくことにした。

00. 文字列の逆順
文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.

Prelude> Data.List.reverse "stressed"
"desserts"

02. 「パトカー」+「タクシー」=「パタトクカシーー」
「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

Prelude> putStrLn $ concat $ zipWith (flip (\x -> flip (:) [x])) "パトカー" "タクシー"
パタトクカシーー

文字と文字を連結して文字列にする関数が見つからず、変な関数を作成してしまった。また、putStrLnを使わないと、コードが表示される。

03. 円周率
"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

Prelude> map length $ words "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechani
cs."
[3,1,4,1,6,9,2,7,5,3,5,8,9,7,10]

wordsという関数は久しぶりに使った。

04で詰まったのこれで終わりかも。

Java Se 8 実践プログラミングを読んで記憶に残った3点

Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング

Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング

1. object::staticMethodでstaticメソッドの第一引数にobjectを指定したメソッド
分かりにくい仕様だと感じたけれど、使ってみたい。
2. 実質的final
局所クラスでは、外側のスコープのfinal変数を参照することができたが、
それが緩和されて、final宣言されていない実質的にfinalな変数を参照できるようになった。
3. インターフェイスにstaticメソッドの定義
インターフェイスにstaticメソッドが定義できるようになった。
クラス名 + sや+ Utilをつけたクラスを定義してきたが、
これからはインターフェイスを作る。
インターフェイスにstaticメソッドを作るのが分かりやすいか別だが、
classに定義するよりは良い。