3

ユーザーが私のプログラムを操作するたびに何かを変更する方法を見つけるのに苦労しています。説明するのが難しいので、ここに例を示します (Haskell + wxhaskell):

simulate :: Int -> Frame () -> IO ()
simulate qNr window = do
 fdata <- readFile "qarchive"
 case (split (listTake (split fdata '\n') qNr 0) '#') of
  (qst:a:b:c:coralt:answer:x) -> do
   -- GUI Controls Initialization (buttons,text,etc...) 
   nextButton <- button window [text := "Next Question ->", on command := set infoField [text := "Next Question"], position := pt 185 155]
   return ()

main :: IO ()
main = start gui

gui :: IO ()
gui = do
 window <- frame [text := "Question program", clientSize := sz 640 480]
 headerText <- staticText window [text := "Title Text", fontSize := 20, position := pt 5 5]
 simulate 0 window
 return ()

「次の質問」ボタンが押されたときにいくつかのウィジェットを変更したい。これらのウィジェットを、ファイルから読み取った値に変更したいと考えています。現在の質問番号を追跡するにはどうすればよいですか? Haskell はそのようなことを許可していないため、実際に questionNumber を変数としてインクリメントすることはできません。やり方は他にもあると思います。

例:

Initialize GUI
Read data from file
If button is pressed, increment question number by 1 and change widgets.

この種の問題に機能的な方法でどのように対処しますか?

4

4 に答える 4

5

関数への引数は変数です。ユーザーが新しい値を入力したら、それらの値を関数に渡します。

たとえば、ユーザー入力に基づいて値を更新する単純なプログラムは次のとおりです。

main = loop 0

loop n = do
    print n
    v <- read `fmap` getLine
    loop (n + v)

「ループ」への再帰呼び出しには、ユーザーが提供した内容に基づいて、毎回異なる値が渡されることに注意してください。

これは、関数型プログラミングにおける基本的な考え方です。命令型プログラムのループ内のローカルで変更可能な変数は、関数型プログラムの再帰関数のパラメーターになります。

于 2010-07-24T18:47:15.633 に答える
2

残念ながら、wxHaskell はイベントベースのフレームワークであるため、Don と ZachS の回答は当てはまりません。

ここでしなければならないことは、命令型言語の場合と同じように、可変変数を割り当てることです。WxHaskell はそのための機能variableを提供します。ここに(不完全な)例があります:

gui = do
        ...
        counter <- variable [value := 1 :: Int]  -- allocate mutable variable
        button  <- button window [ text       := "Count!"
                                 , on command := next counter button]
    where
    next counter button = do
        n <- get counter value         -- get its value
        set button  [text  := show n]
        set counter [value := n+1]     -- set its value

wxHaskell には多くのサンプル ソース コードが付属していることに注意してください。特に、wx/ImageViewer.hs変更可能な変数を備えています。

ただし、このような特別な状況を除いて、疫病のような可変変数を避けることは有益です。(実際、それらは wxHaskell でも混乱を引き起こします。ここで回避するのが難しいだけです。) 代替手段には、コードの再考、パラメーターの蓄積、フォームの型s -> (a,s)と状態モナドの使用が含まれます。

于 2010-07-28T13:56:39.047 に答える
1

関数型言語でこれを行う1つの方法は、関数を介して状態をスレッド化することです。キーボードの状態を取得するなど、一部の機能はおそらくモナドによって処理されるため、自分で処理する必要はありません。例(多かれ少なかれ擬似コード):

someFunction :: SomeDataTypeThatRepresentsState -> a ... -> (SDTTRS, a...) (change to fit reality of course)
someFunction x y .... | x == WeHaveKeyboardInput = someFunction dowhatever.....
                      | someFunction dowhateverelse

それはあなたにどのように始めるかについての考えを与えるはずです。

編集:

モナドについてもっと深く言及すべきだった。モナドは基本的に、通過するすべての状態を隠す方法です。それは単純化されすぎていると私は知っていますが、それはあなたを始めさせます。モナドと処理状態の詳細については、次のリンクを参照してください:http ://www.engr.mun.ca/~theo/Misc/haskell_and_monads.htm

于 2010-07-24T18:41:25.490 に答える
0

Hackage の simple-observer パッケージもチェックしてみてください。(開示: 私はパッケージのメンテナーです。)

これは Observer デザイン パターン (イベント ベースのフレームワークで「毎回何かを変更する...」という問題を解決するための単なるチケット) の Haskell 実装であり、変更可能な状態に MVars を使用します。ここでさらに議論しているブログ投稿があります

あなたとまったく同じ問題に直面したときに、このパッケージを作成しました。

于 2010-09-14T15:56:04.727 に答える