2017-07-31 12 views
0

私はハスケルには新しく、おそらく本当に愚かな質問をしています。 は、私が実行するには、次のコードを取得しよう:doブロックの返信ケース

asdf :: Maybe a -> Maybe a 
asdf k = do 
    return $ case k of 
       Nothing -> Nothing 
       Just x -> Just x 

私はリターンが非感があるだけでやるということ、これは基本的にfmapであることを知っていると。私が実際にやりたいことは次のとおりです

vote :: PostId -> Bool -> Maybe (Int, Int) 
vote id v = do 
    p <- runSQL $ P.get id 
    return $ case p of 
    Nothing -> Nothing 
    Just p -> do 
       let uv = postUpvotes p 
       let dv = postDownvotes p 
       let nuv = if v then uv + 1 else uv 
       let ndv = if not v then dv + 1 else dv 
       runSQL $ update id [PostUpvotes =. nuv, PostDownvotes =. ndv] 
       (nuv, ndv) 

これは複数の問題があります。私の最初の例で何が間違っていますか? 2番目の問題へのアプローチは完全に間違っているのでしょうか?あなたはどのようにそれを書いていますか?

+2

'runSQL'の種類は何ですか?純粋ではないと仮定して、 'Maybe(Int、Int)'を返す関数内でそれを実行することはできません。 – Lee

+0

これはこのチュートリアルのものです:https://www.spock.li/tutorials/rest-api – lbrndnr

+1

IOを行うことはできません。IOのモナドに値を返さない限り、おそらく 'IO(Maybe(Int、 Int)) ')。 – chi

答えて

2

最初のコードサンプルにreturnは必要ありません。

returnはHaskellで何を意味するのか分かりましたか?他のプログラミング言語ではreturnのようなものではありません。ほとんどの言語では、値を指定して呼び出し関数に制御を戻す制御文の流れ。ハスケルでは、誤解を招く名前の関数です。この場合

あなたが言う必要があります:Haskellのdo表記で

asdf k = 
    case k of 
      Nothing -> Nothing 
      Just x -> Just x 

はIOモナドのような、一緒に使用されます。ここで問題を混乱させるのは、実際にはMaybeもモナドであるという事実です。実際、そこには最も単純なモナドがあります。何らかのコンテキストで動作する関数のデイジーチェーンが必要な場合にのみ、モナドを使用する必要がありますが、ここではそうではありません。

2番目の例に移りますと、runSQLは外部とやりとりする必要がありますので、タイプaの場合はIO aという形式のものが返されます。この場合、であり、外界の文脈で関数のデイジーチェーンを実行するので、モナドを使用する必要があります。

return、この場合には、タイプ

return :: a -> IO a 

があり、機能である、それは純粋な値をとりモナドのコンテキストでそれをラップしますので、それは本当にpureと呼ばれている必要があります。 (あなたがApplicative Functorsに行くとreturnというバージョンがあり、それはpureと呼ばれます)。

モナドに関するルールは、一度モナドの状況になると出ることができないということです。コンテキスト内の値について純粋な計算を実行できますが、結果はモナドのコンテキストにとどまります。そのコンテキストは、「IO」のようなタイプで表されます。したがって、この場合、関数のタイプは

である必要があります。しかし、それを試してもまだ機能していないことがわかります。 caseの最初のブランチは、Nothingを返すので、問題ありません。しかし、2番目のブランチは、IOアクション後に(nuv, nvd)を返そうとするため、タイプエラーが発生します。 returnを除外しようとしましたが、実際には最初のブランチにはreturn Nothing、次に2番目のブランチにはreturn $ Just (nuv, nvd)が必要です。

なお、値ごとに新しいletは必要ありません。あなたは言うことができる

let 
    foo = 1 
    bar = 2 
return (foo, bar) 
+0

私はそれを購入していないかもしれませんが、おそらく最も単純なモナドがあります。おそらくリーダーは単純ですが、あなたが同意しなくてもアイデンティティははるかに単純です。 – amalloy

+2

また、 'vote'関数は、第2ブランチでIOを実行しようとするので、あなたが提案するよりも修正が必要です。 'return $ case ... 'の代わりに、{Nothing - > return Nothing;のケースpのように見える必要があります。ちょうどp - > do ... return(nuv、ndv)} '。 – amalloy

+0

@amalloy:あなたは正しいです。投稿が更新されました。 –

関連する問題