2

行機能を使用して、入力を取得し、関数に送信する前に多くの変数を分割しています。run 関数を見て、次のエラーが発生する理由を教えてください。ln の最初の文字列を seq に代入すればよいようですが、エラーが発生します。

エラー: 不誠実.hs:33:11:
    予想される型 `[t]' を推測された型 `Char' と一致させることができませんでした
    'do' 式: seq <- ln !! 0
    式では:
        do ln <- 行 s
           seq <- ln !! 0
           状態 <- ln !! 1
           l1 <- listDouble (ln !! 2)
           ....
    「実行」の定義では:
        run s = do ln <- lines s
                   seq <- ln !! 0
                   状態 <- ln !! 1
                   ....
コードは続きます...

import Char

maximumInd :: (Double, Double) -> Int
maximumInd (d1,d2) | maximum [d1,d2] == d1 = 1
                   | maximum [d1,d2] == d2 = 2

scoreFunction :: String -> Int -> [Double] -> [Double] -> Double -> Double -> (Double,Double)
scoreFunction string (-1) l1 l2 t1 t2 = (0.5, 0.5)
scoreFunction string index l1 l2 t1 t2 = ((fst (scoreFunction string (index-1) l1 l2 t1 t2)) * (l1!!num) * (tr (maximumInd (scoreFunction string (index-1) l1 l2 t1 t2))!!1), (snd (scoreFunction string (index-1) l1 l2 t1 t2)) * (l2!!num) * (tr (maximumInd (scoreFunction string (index-1) l1 l2 t1 t2))!!2))
    where
        num = digitToInt (string!!index)
        tr n | n == 1 = l1
             | n == 2 = l2

--split is stolen from teh webs http://julipedia.blogspot.com/2006/08/split-function-in-haskell.html
split :: String -> Char -> [String]
split [] delim = [""]
split (c:cs) delim
   | c == delim = "" : rest
   | otherwise = (c : head rest) : tail rest
   where
       rest = split cs delim

readDouble :: String -> Double
readDouble s = read s :: Double

listDouble :: String -> [Double]
listDouble s = map readDouble $ split s ' '

run :: String -> String
run s = do
    ln <- lines s
    seq <- ln!!0
    states <- ln!!1
    l1 <- listDouble (ln!!2)
    l2 <- listDouble (ln!!3)
    tr1 <- readDouble (ln!!4)
    tr2 <- readDouble (ln!!5)
    show maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)

main = do
    putStrLn "Please compose a test job for Viterbi."
    putStrLn "First line: A sequence with language [1,9]."
    putStrLn "Second line: The number of states."
    putStrLn "For the next 2 lines: space delimited emission probabilities."
    putStrLn "For the 2 lines after that, transmission probabilities."
    putStrLn "Then do ./casino < filename "
    interact run
4

5 に答える 5

5

まず、コンパイラがそれをどのように解釈しているかを見てみましょう。

run :: String -> String

Stringです[Char]

run s = do
    ln <- lines s
    ...

物事を大幅に単純化すると、doブロックは で「実行」する必要がありMonadます。これは、 type の値を「返す」ことを意味します(Monad t) => t a。この関数は を返している[Char]ので、doブロックは を返します[Char]。つまり、Monadです[]( と読む[a][] a、より明確になります)。

私の別の答えからコピーすると、

物事を大幅に単純化すると、IO モナドの do ブロックでは、すべての行が次のいずれかになります。

  • 「IO a」型の値を返すもの。その中の「a」型の値は破棄されます (したがって、「a」は多くの場合「()」です)。
  • <- 式。同じことを行いますが、「a」型の値を破棄する代わりに、<- の左側に名前を付けます。
  • 値に名前を付けるだけの let

ここでは、モナドではなく、IOモナドにい[]ます。したがって、 の右側の式<-[a].

したがって、doブロックの最初の行で:

    ln <- lines s

ここでの型は[[Char]]であり、したがって の型はlnです[Char]

次の行で:

    seq <- ln!!0

ここln!!0には typeCharがありますが、あなたは[]モナドにいるので、ある種のリストを期待しています。これが、コンパイラのエラー メッセージの原因です。

解決策は、表記法を使用する代わりにdo、単純なletブロックを使用することです。

run :: String -> String
run s = let
        ln = lines s
        seq = ln!!0
        states = ln!!1
        l1 = listDouble (ln!!2)
        l2 = listDouble (ln!!3)
        tr1 = readDouble (ln!!4)
        tr2 = readDouble (ln!!5)
    in show maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)

私はこのブロックをコンパイルしていませんが、他に何か問題があるとしても、やり直すには十分なはずです。

于 2008-11-16T03:06:10.710 に答える
0

run は String -> String 型であるため、おそらく do 表記は必要ありません[1]。これを行うことをお勧めします:

  1. listDouble 関数の下のすべてをコメントアウトしてロードし、コンパイルされることを確認します。
  2. 期待するファイルのようにフォーマットされたテスト値を追加します。何かのようなもの:

     t = "[1,9]\n3\n1.0 1.0 1.0\n1.0 1.0 1.0\n1.0\n1.0"  
    
  3. 実行時に定義している値の最上位レベルのテスト値を追加します

    ln = lines t
    seq = ln!!0
    states = ln!!1
    l1 = listDouble (ln!!2)
    l2 = listDouble (ln!!3)
    tr1 = readDouble (ln!!4)
    tr2 = readDouble (ln!!5)   
    
  4. scoreFunction の型シグネチャを使用して、その関数への引数を作成し、次に run の残りの部分を作成し、最後に main を作成します。

Hugs、ghciなどの通訳の使い方を学びましょう。:r および :t コマンドを学びます。例(私はカリー化を使用して、関数の引数のすべてではなく一部を指定しています):

  :t scoreFunction
  :t scoreFunction ""
  :t scoreFunction 3445

これを使用して、正しい軌道に乗っているかどうかをシステムが判断できるようにすることができます。トップレベルでこれを行うと、Prelude.seq 関数との競合が発生します - seq の名前を変更するか、自分の seq を Main.seq として参照します。

Haskell は初心者には不可解なエラー メッセージで悪名高いので、現在の実験をコメント アウトするか (上記の手順 1 で行ったように)、コンパイル可能なバージョンに定期的にロールバックすることをお勧めします。エディタは機能を元に戻します。

[1] 文字のリストである Strings が Monad クラスのインスタンスであるためだと思いますが、それはかなり高度です

于 2008-11-16T04:03:03.327 に答える
0

これが正しいかどうかはわかりませんが、使用しているように見えるので、代入演算子ではないという事実に問題がある可能性があります。基本的に、モナドから値をアンパックします。しかし、それがあなたの問題の原因であるかどうかはわかりません。<-

于 2008-11-16T02:39:32.903 に答える
0

リストは Haskell のモナドであり、次のように定義されていることを思い出してください。

instance Monad [] where
    m >>= f  = concatMap f m
    return x = [x]
    fail s   = []

したがって、コードを取得すると、次のようになります。

do {ln <- lines "hello, world"; ln!!0}

これは、バインド表記を使用した以下と同等です。

lines "hello world" >>= (\ln -> ln!!0)

またはより簡潔に:

lines "hello world" >>= (!!0)

リストモナドの定義を使用して、次のように書き直すことができます。

concatMap (!!0) (lines "hello, world")

これは次と同等です:

concat $ map (!!0) (lines "hello, world")

行 "hello, world" は ["hello, world"] を返すため、それに対するマッピング (!!0) は文字列 "h" を生成します。[Char] 型ですが、concat には [[t]] 型が必要です。Char が [t] と一致しないため、エラーが発生します。

do 表記ではなく let などを使用してみてください。

編集:

だから、これはあなたが望むものだと思います。do ではなく let を使用します。

run :: String -> String
run s = let ln = lines s
            seq = ln!!0
            states = ln!!1
            l1 = listDouble (ln!!2)
            l2 = listDouble (ln!!3)
            tr1 = readDouble (ln!!4)
            tr2 = readDouble (ln!!5)
        in show $ maximumInd (scoreFunction seq (length seq) l1 l2 tr1 tr2)
于 2008-11-16T02:58:52.100 に答える
0

ええ、ミパディは正しいと思います。do 表記は >>= に変換され、リスト モナドへの呼び出しを返します。

run s = do
    ln <- lines s
    seq <- ln!!0
    states <- ln!!1

によって返されるリストを取得しlines s、seq と状態に対して、ln は毎回そのリストの文字列になります。したがって、実際には ln!!0 を使用すると、その文字列の最初の文字が取得されます。ただし、そこの右側にリストが必要です<-。覚えているのはこれくらいです。Haskellでそれらのことをしてからかなりの時間が経ちました:)

于 2008-11-16T02:59:34.390 に答える