2016-06-01 19 views
1

私はHaskellを初めて使っていて、シンプルなプログラムを書いて、最大の要素を見つけようとしています。 1つ1つ比較する値を受け取ります。私が持っている最大の要素maxi変数、それはインデックスです - maxIdxです。ここに私のプログラムです:シンプルなHaskellプログラムが正しく動作しない

loop = do 
    let maxi = 0 
    let maxIdx = 0 
    let idx = 0 
    let idxN = 0 
    replicateM 5 $ do 
     input_line <- getLine 
     let element = read input_line :: Int 

     if maxi < element 
     then do 
      let maxi = element 
      let maxIdx = idx 
      hPutStrLn stderr "INNER CHECK" 
     else 
      hPutStrLn stderr "OUTER CHECK" 

     let idx = idxN + 1 
     let idxN = idx 

     print maxIdx 

    loop 

私は要素が来るのを知っているにもかかわらず、より大きなから小さい(5、4、3、2、1)プログラムは、INNERが(それが唯一の最初の要素のために起こるはずのすべての時間をチェック入り始めています!)とmaxIdxは常に0です。 私は間違っていますか? ありがとうございます。

+2

各繰り返しで 'maxi'を印刷してみてください。それはあなたにヒントを与えるはずです。それに、あなたがハスケルを使っているとは思わない。 – alf

+0

** hPutStrLn stderrのint値をどのようにpringできますか?**?はい、私はそれを最善の方法でusuingしていないことを知っています、私はそれを試しています:)。 – SoldierKB

+6

ポイントは、それらは_vary._ではないという点で "変数"ではありません。これらは値であり、スコープはあなたが現在行っている 'do'演算子に限定されています。 – alf

答えて

9

とにかく、楽しく過ごしましょう。

loop = do 
    let maxi = 0 
    let maxIdx = 0 
    let idx = 0 
    let idxN = 0 
    replicateM 5 $ do 
     input_line <- getLine 
     let element = read input_line :: Int 

     if maxi < element 
     then do 
      let maxi = element 
      let maxIdx = idx 
      hPutStrLn stderr "INNER CHECK" 
     else 
      hPutStrLn stderr "OUTER CHECK" 

     let idx = idxN + 1 
     let idxN = idx 

     print maxIdx 

    loop 

は、特にハスケルコードではありません(特に正しくはありません)。

ハスケリエならば作ろう。

ここでは何をしますか?私たちは無限のループを持っています。無限ループは、5行目を読んでいて、それに何かをしてから、特別な理由なしに再び呼びます。

のは、それを分割してみましょう:

import Control.Monad 

readFiveLines :: IO [Int] 
readFiveLines = replicateM 5 readLn 

addIndex :: [Int] -> [(Int, Int)] 
addIndex xs = zip xs [0..] 

findMaxIndex :: [Int] -> Int 
findMaxIndex xs = snd (maximum (addIndex xs)) 

loop ::() 
loop = loop 

main :: IO() 
main = do xs <- readFiveLines 
      putStrLn (show (findMaxIndex xs)) 

sndはタプルから2番目の要素を返します。 readLnは本質的にread . getLineです。 zipは2つのリストを取り、ペアのリストを返します。 maximumが最大値を見つけます。

私はloopを元の美しさにそのまま残しました。

あなたはsomething (huge expression)が(単にその右オペランドにその左オペランドを適用$something $ huge expressionと交換することができることを覚えていればあなたもHaskellierすることができ、かつ機能が.と組み合わせることができます:f (g x)(f . g) x、またはf . g $ xと同じです(参照してください?それはまた、左側のために働いている!)。また、zip x yデバッグプリントとしてx `zip` y

import Control.Monad 

readFiveLines :: IO [Int] 
readFiveLines = replicateM 5 readLn 

addIndex :: [Int] -> [(Int, Int)] 
addIndex = (`zip` [0..]) 

findMaxIndex :: [Int] -> Int 
findMaxIndex = snd . maximum . addIndex 

main :: IO() 
main = do xs <- readFiveLines 
      putStrLn . show . findMaxIndex $ xs 

ように書き換えることができ、パッケージはありstderrDebug.Traceと(したがって、その名前showでフォーマットされた)最初の引数を印刷する機能traceShowと呼ばれ、その第二のを返します引数:

findMaxIndex :: [Int] -> Int 
findMaxIndex = snd . (\xs -> traceShow xs (maximum xs)) . addIndex 

あなたはどんな式にタップして、に来るのかを確認することができます(と値は約何 - することができますshowタプル、リストなど)

+0

空リストを作成するにはどうすればよいですか? – SoldierKB

+0

私は本当に[あなたを偉大な良いのためのハスケルを学ぶ](http://learnyouahaskell.com/)、すなわち[リストの章](http://learnyouahaskell.com/starting-out## intro-to-lists) - これはStack Overflowで尋ねる質問とはまったく異なります。しかし、私たちはそれを試している間に '[]'を試してください – alf

+0

ありがとう、私はそれをチェックし、それが動作するように動作します^^。 'snd'、' zip'、 'maximum'の全てを知り、機能的な方法ではないと思っていても、うまく動作していない時がありました。 – SoldierKB

0

私はアルフの答えがとても良いと思いますが、それが価値があるのは、あなたの意図を解釈する方法です。

{-# LANGUAGE FlexibleContexts #-} 

module Main where 

import System.IO 
import Control.Monad.State 

data S = S { maximum :: Int 
      , maximumIndex :: Int 
      , currentIndex :: Int } 

update :: Int -> Int -> S -> S 
update m mi (S _ _ ci) = S m mi ci 

increment :: S -> S 
increment (S m mi ci) = S m mi (ci+1) 

next :: (MonadIO m, MonadState S m) => m() 
next = do 
    S maxi maxIdx currIdx <- get 

    input <- liftIO $ getLine 
    let element = read input :: Int 

    if maxi < element 
    then do 
    modify (update element currIdx) 
    liftIO $ hPutStrLn stderr "INNER CHECK" 
    else 
    liftIO $ hPutStrLn stderr "OUTER CHECK" 

    modify increment 

run :: Int -> IO S 
run n = execStateT (replicateM_ n next) (S 0 0 0) 

main :: IO() 
main = do 
    S maxi maxIdx _ <- run 5  
    putStrLn $ "maxi: " ++ (show maxi) ++ " | maxIdx: " ++ (show maxIdx) 

これは、ステートフルな計算とIOを組み合わせるためにモナドトランスを使用します。 get関数は現在の状態を取得し、modify関数を使用すると状態を変更できます。

+0

犯行はありませんが、ハスケルの仕組みを理解していない初心者にとっては、この回答は特に役に立ちません。 – Emil

+0

違反はありません。いつか誰かを助けるかもしれない。 – user2297560

+0

助けてくれてありがとう。 – SoldierKB

関連する問題