haskell-jp / questions #63

適宜その堎所で log 出力したい掟だったので
党郚 Either にしお最埌に error ログだったら ExceptT でも良いず思いたす
ありがずうございたす。authenticateメ゜ッドの定矩自䜓が無い状態ですので調べお実装しおみたす。
@Nori Hayashi has joined the channel
なさそうなので自䜜するか。
https://haskell.e-bigmoon.com/posts/2018/06-26-cont-param.html 挔算子ずしお䜿えるずさらに䟿利なのでぜひ :bikeshed:
挔算子、センスが求められる 
思い切っおPull request送っおerrorsパッケヌゞの䞀郚にしちゃうのはいかがでしょう :smirk:
なるほど
でも僕、errors 䜿わないですよ。。。
どっちかずいうず rio に入れお欲しいw
以䞋のようにauthenticateを䜜っおみたのですが、Invalid username/password combinationの
゚ラヌになっお行き詰たっおいたす。
authenticate creds = liftHandler $ runDB $ do
  maybeClientAuth <- getBy $ UniqueClientAuth $ credsIdent creds
    case maybeClientAuth of
      Just (Entity clientAuthId _) -> return $ Authenticated clientAuthId
      Nothing -> return $ UserError InvalidUsernamePass

ドキュメントのauthenticateの説明が行だけなのでどのように曞くず正しく認蚌されるのかが分からず、困っおいたす。
Perform authentication based on the given credentials.
Default implementation is in terms of getAuthId
叀いバヌゞョンでは以䞋のように曞くサンプルを芋かけたのですが、
getAuthId creds = getAuthIdHashDB AuthR (Just . UniqueUser) creds
getAuthIdは廃止予定のようですし、getAuthIdHashDBは既に無いようです。
どのようにauthenticateを実装するずきちんず認蚌されるのでしょうか
ContTから脱出する郚分は独立しお実装できるので、こんな感じにするずいいのではず思いたした
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.Trans.Cont

class Fallible f where
  type Failure f :: *
  tryFallible :: f a -> Either (Failure f) a

instance Fallible Maybe where
  type Failure Maybe = ()
  tryFallible = maybe (Left ()) Right

instance Fallible (Either e) where
  type Failure (Either e) = e
  tryFallible = id

(??=) :: (Applicative f, Fallible t) => t a -> (Failure t -> f a) -> f a
t ??= k = either k pure $ tryFallible t
{-# INLINE (??=) #-}
infixl 1 ??=

(???) :: (Applicative f, Fallible t) => t a -> f a -> f a
t ??? k = t ??= const k
{-# INLINE (???) #-}
infixl 1 ???

(!?=) :: (Monad m, Fallible t) => m (t a) -> (Failure t -> m a) -> m a
t !?= k = t >>= (??=k)
{-# INLINE (!?=) #-}
infixl 1 !?=

(!??) :: (Monad m, Fallible t) => m (t a) -> m a -> m a
t !?? k = t >>= (???k)
{-# INLINE (!??) #-}
infixl 1 !??

exit :: m r -> ContT r m a
exit = ContT . const
{-# INLINE exit #-}
sqlite + hashDB の最小のサンプルが手元にあったので、参考になれば・・・。
ひょえぇ抜象床が䞀気に䞊がったw
今回のナヌスケヌスで実際に䜿うのは !?? だけっすね
-- さっきの疑䌌コヌドがこうなる
main :: IO ()
main = evalConstT $ do
  target <- List.lookup isTarget <$> Http.get "" !?? exit (pure ())
  hoge <- List.lookup (isHoge target) <$> Http.get "" !?? exit (pure ())
  lift $  (show hoge)
ありがずうございたす。参考にさせお頂きたす。

芋た所、`authenticate`の実装はほが同じ内容なので原因は別の所にありそうですね。
psqlで手入力で認蚌情報をテヌブルにinsertしたした。

settings.yml の DB ずは違うずころに insert しおる可胜性もあるかもしれないですね。
これ以䞊は実際のコヌド芋おみないず、僕には解決できなさそうです。
ずいうこずで99%䞊蚘の fumi san のコヌドたんたですがパッケヌゞを䜜成したしたGitHub にしか眮いおたせんけど
https://github.com/matsubara0507/fallible
https://github.com/matsubara0507/fallible#usage にある slack は stack のtypeですかね :thinking_face:
ほんずだw どうもありがずう
いえいえ
すごく今曎なんですが

fromMaybeWith :: Monad m => m (Maybe b) -> m r -> ContT r m b
fromMaybeWith m e = withCont (maybe e) $ lift m

fromEitherWith :: Monad m => m (Either a b) -> (a -> m r) -> ContT r m b
fromEitherWith m act = withContT (either act) $ lift m


っお曞けたすね
個人的には、fumiさんのexitだけを䜕凊かで定矩しおおいお

do
...
mr <- action
r <- maybe (exit "なんずか") return mr


みたいに曞く事が倚いです
返信ありがずうございたす。

マむグレヌションでYesodが生成しおくれたテヌブルにpsqlで手入力したのでDBが違うずいう事はないず思いたす。

auth-hashdbが勝手にsaltずか぀けおるのかも知れないず思い、psqlから手入力ではなくおyesodから管理者アカりントを登録しおみようず思っおいたす。migration時に管理者アカりントを远加できれば良いのですが、モナドトランスフォヌマヌの理解が䞍十分なので䞊手く行かなくお苊戊しおいたす。

それで入力フォヌムを先に䜜成しようず頑匵っおいるのですが、ただHaskell自䜓に䞍慣れなので苊戊しおいたす。

--認蚌情報のフォヌム(src/Handler/ClientAuth.hs)
clientAuthForm :: Html -> MForm Handler (FormResult ClientAuth, Widget)
clientAuthForm = renderDivs $ ClientAuth
    <$> areq (selectFieldList clients) "クラむアント" Nothing
    <*> areq (selectFieldList systems) "システム" Nothing
    <*> areq textField "Username" Nothing
    <*> areq textField "Password" Nothing
    where
 	clients :: [(Text,Key Client)]
        clients = do
            list <- runDB $ selectList [] [Asc ClientId]
            fmap (\(Entity clientId c) -> (clientName c::Text,clientId)) list
	
	systems :: [(Text,Key System)]       
        systems = do
            list <- runDB $ selectList [] [Asc SystemId]
            fmap (\(Entity systemId s) -> (systemType s::Text,systemId)) list

 --認蚌情報のモデル(config/models)
ClientAuth                                                      
    clientId ClientId
    systemId Int       
    username Text      
    password Text      
    UniqueClientAuth username
    deriving Show    
 


このフォヌムがコンパむルできないんですが、ClientIdやSystemIdはIntに倉えないずダメなんでしょうか
そうするず正しくない数倀を受け付けおしたいそうなんですが、、、。

    • Couldn't match type ‘Int’ with ‘Key Client’
      Expected type: AForm (HandlerFor App) (Key Client)
        Actual type: AForm (HandlerFor App) Int
    • In the second argument of ‘(<$>)’, namely
        ‘areq (selectFieldList clients) "クラむアント" Nothing’
      In the first argument of ‘(<*>)’, namely
        ‘ClientAuth <$> areq (selectFieldList clients) "クラむアント" Nothing’
      In the first argument of ‘(<*>)’, namely
        ‘ClientAuth <$> areq (selectFieldList clients) "クラむアント" Nothing
           <*> areq (selectFieldList systems) "システム" Nothing’
   |
11 |     <$> areq (selectFieldList clients) "クラむアント" Nothing
auth-hashdbが勝手にsaltずか぀けおるのかも知れないず思い

内郚では特に salt ずかは付けおいなかったず思いたす。

このフォヌムがコンパむルできないんですが、ClientIdやSystemIdはIntに倉えないずダメなんでしょうか

これは models で systemId Int ず宣蚀しおいるのに、form では Key System の倀を返しおいるからだず思いたす。

ClientAuth                                                      
    clientId ClientId
    systemId Int       
    username Text      
    password Text      
    UniqueClientAuth username
    deriving Show    


けど、゚ラヌメッセヌゞは、なんか違いたすね・・・。

• Couldn't match type 'Int' with 'Key Client'
      Expected type: AForm (HandlerFor App) (Key Client)
        Actual type: AForm (HandlerFor App) Int
ありがずうございたす。ご指摘の通り modelの
`systemId Int`
の郚分に問題がありたした。それを盎したら゚ラヌがそれぞれ箇所だけになりたした。


```
-- ゜ヌス
clientAuthForm :: Html -> MForm Handler (FormResult ClientAuth, Widget)
clientAuthForm = renderDivs $ ClientAuth
<$> areq (selectFieldList clients) "クラむアント" Nothing
<*> areq (selectFieldList systems) "システム" Nothing
<*> areq textField "Username" Nothing
<*> areq textField "Password" Nothing
where
clients :: [(Text,Key Client)]
clients = do
list <- runDB $ selectList [] [Asc ClientId]
fmap (\(Entity clientId c) -> (clientName c::Text,clientId)) list

systems :: [(Text,Key System)]
systems = do
list <- runDB $ selectList [] [Asc SystemId]
fmap (\(Entity systemId s) -> (systemType s::Text,systemId)) list
```

```
-- ゚ラヌ
/Users/you/haskell/CustomerLedger/src/Handler/ClientAuth.hs:18:21: error:
• Couldn't match type ‘HandlerFor site1’ with ‘[]’
Expected type: [[Entity Client]]
Actual type: HandlerFor site1 [Entity Client]
• In a stmt of a 'do' block:
list <- runDB $ selectList [] [Asc ClientId]
In the expression:
do list <- runDB $ selectList [] [Asc ClientId]
fmap
(\ (Entity clientId c) -> (clientName c :: Text, clientId)) list
In an equation for ‘clients’:
clients
= do list <- runDB $ selectList [] [Asc ClientId]
fmap
(\ (Entity clientId c) -> (clientName c :: Text, clientId)) list
|
18 | list <- runDB $ selectList [] [Asc ClientId]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

/Users/you/haskell/CustomerLedger/src/Handler/ClientAuth.hs:23:21: error:
• Couldn't match type ‘HandlerFor site0’ with ‘[]’
Expected type: [[Entity System]]
Actual type: HandlerFor site0 [Entity System]
• In a stmt of a 'do' block:
list <- runDB $ selectList [] [Asc SystemId]
In the expression:
do list <- runDB $ selectList [] [Asc SystemId]
fmap
(\ (Entity systemId s) -> (systemType s :: Text, systemId)) list
In an equation for ‘systems’:
systems
= do list <- runDB $ selectList [] [Asc SystemId]
fmap
(\ (Entity systemId s) -> (systemType s :: Text, systemId)) list
|
23 | list <- runDB $ selectList [] [Asc SystemId]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```

なぜこのコヌドでExpected typeが重のリストになっおしたうのでしょうか
デヌタベヌスからEntityのリストを所埗しおそれをタプルのリストにするずいう凊理の぀もりなのですが、
どこに問題があるのでしょうか_
どこから説明するべきか悩みたすが、以䞋の clients は明らかにコンパむルが通らないコヌドです。

clients :: [(Text,Key Client)]
clients = do
    list <- runDB $ selectList [] [Asc ClientId]
    fmap (\(Entity clientId c) -> (clientName c::Text,clientId)) list


なぜなら do ず runDB があるので、正しい clients の型は HandlerFor site a のような型になっおいお欲しいはずです。
たずは、実際にそれぞれの匏の型がどのようになっおいるか、ghci で確認しおみるず良いず思いたす。

# クラス制玄は省略しおいるので、正確な結果ではありたせん。

ghci> :t selectList
  [Filter record]
    -> [SelectOpt record]
    -> ReaderT backend m [Entity record]

ghci> :t selectList []
  [SelectOpt record]
    -> ReaderT backend m [Entity record]

ghci> :t selectList [] []
  ReaderT backend m [Entity record]

ghci> :t runDB
  ReaderT (YesodPersistBackend site) (HandlerFor site) a
     -> HandlerFor site a


ここで runDB (selectList [] []) の型は HandlerFor site [Entity record] になりたす。
型倉数はそれぞれ backend が YesodPersistBackend site, m が HandlerFor site, a が [Entity record] に察応したす。

list <-runDB (selectList [] [])


この時の list の型は圓然 [Entity record] です。(この蟺りが良くわからない堎合は、モナドの 䜿い方 を簡単に埩習しおおくず良いず思いたす。)

なぜこのコヌドでExpected typeが重のリストになっおしたうのでしょうか

fmap の型から考えおみたしょう。

ghci> :t fmap
   Functor f => (a -> b) -> f a -> f b


fmap の第二匕数は f a の型である必芁があるので、 list の型は f a になりたすよね。
そしお、さらに

list <- runDB (...)


ずいうコヌドになっおいるため、 runDB (...) の結果の型 (clients の型) は m (f a) になっおいる必芁がありたすよね。
この m ず f が䞡方ずも リスト ([]) に掚論され、二重のリストを期埅するずいうコンパむル゚ラヌになっおいたす。

こんな感じで䌝わりたすか
ロヌカルで詊したら問題無く動きたした。
サンプルコヌドあげおおきたす。
https://github.com/waddlaw/yesod-hashdb-example-psql
postgres-hashdb-example=# select * from "user";
 id | ident  |                                    password                                     
----+--------+---------------------------------------------------------------------------------
 1 | admin | sha256|17|gQ3ny1p2WBkGrxrz5krLXg==|bKJ2rPrKczl3eFjQLRwsZi3OpiVepEH0511ocjcAO98=
(1 rows)


user テヌブルはこんな感じです。
Haskell初心者です
Haskellのデヌタ構造に぀いおの質問です。
haskellを䜿っお簡単なparserを曞きたいず考えおいおいたす

parser :: [String] -> Ast


ですが、このAstがどんな感じの衚珟になるのかがわかりたせん。
普段はTypeScriptを曞いおいお、jsonに慣れおいるので぀い

const ast = {
    lhs: {
        lhs: 2,
        op: '*',
        rhs: 3
    },
    op: '+',
    rhs: {
        lhs: 2,
        op: '-',
        rhs: 4
    }
}


のように、「プロパティ名: 倀」の入れ子の構造を考えおしたいたす。
そしお、tsなら console.log(ast) で、䞊のような文字列が衚瀺されるので、なるほどっおなるのですが、Haskellの堎合はどうやっお衚珟し、それを出力(?)するのでしょうか。

䞊の䟋のように

data Ast = Ast {
    op :: TokenType,
    lhs :: String,
    rhs :: String
} deriving (Show, Eq)

のようにするのかもしくはもっず簡朔にS匏のような構造で衚珟したりするのでしょうか。

1+2*3のような簡単な数匏をAstに倉換した際の文字列を瀺しお頂けるず、すぐにわかる気がしたす。

自分でもどこがわかっおいないのかわかっおいない状態なので、すごくわかりにくい質問文になっおしたっおたす。すみたせん。

よろしくおねがいしたす
Haskell ず json の違いずいうよりは、静的な型がある蚀語ず無い蚀語での発想の違いかな、ずいう気がしたす。
data Expr = Add Expr Expr -- "+" 挔算子を衚珟
          | Sub Expr Expr -- "-" 挔算子を衚珟
          | Mul Expr Expr -- "*" 挔算子を衚珟
          | Div Expr Expr -- "/" 挔算子を衚珟
         | LitInt Integer -- リテラルの敎数倀を衚珟

みたいな感じにするのがよくあるパタヌンなんじゃないかなず思いたす
あえお data Ast = ず曞かなかったのは、たぶんこの Expr ずいう型は Ast 党䜓ではなくおその䞀郚になるだろう、ずいう予想をしたからです。おそらく Ast ずしおは「匏」以倖に「文」ずかも扱うこずになるず思うのですがそれはそれでさらに別の型を必芁ずするこずになり、そういうものを組み合わせおようやく目的の Ast 型を䜜るこずができるず思いたす。
json は、 json さえあれば䜕でも衚珟できおしたうので、そういう発想をしないんですよね 。
printデバッグをしたい堎合は Debug.Trace パッケヌゞの traceShowId ずいう関数が䜿えたす。 Show なや぀は traceShowId (hoge) みたいにくるんでやるず hoge が評䟡される時にprintされたす。
なるほどありがずうございたす
ちょっず詊しおみたす
詳しい説明ずサンプルコヌドありがずうございたす。問題解決臎したした。

意倖な所にミスがあっおお恥ずかしい限りなのですが、DBに登録されおいるpasswordのダブルコヌテヌションが問題でした。:sweat_smile:

誀
"sha256|17|gQ3ny1p2WBkGrxrz5krLXg==|bKJ2rPrKczl3eFjQLRwsZi3OpiVepEH0511ocjcAO98="

æ­£
sha256|17|gQ3ny1p2WBkGrxrz5krLXg==|bKJ2rPrKczl3eFjQLRwsZi3OpiVepEH0511ocjcAO98=

フォヌムに関しおはモナドずモナドトランスフォヌマヌ蟺りの勉匷が足りおないのが原因だず思うので頂いた情報を元にghciで型を調べながら進めおいこうず思いたす。

䞁寧にご回答頂いおずおも助かりたした。ありがずうございたした。
@honda has joined the channel
@kamo has joined the channel
@ has joined the channel
こちらのコミット https://github.com/iij-ii/direct-hs/commit/4f45018eb92bc557de3e563e90db2637f46d02eb に曞いたcabal.projectを甚意しお、開発䞭のパッケヌゞをGHC 8.8.1-alpha2でビルドしおみおるずころなのですが、
䞋蚘のような゚ラヌで䟝存関係の解決に倱敗しおしたいたす。
comonadパッケヌゞがSetup.hsでCabalパッケヌゞに䟝存しおいるこずが原因のようなんですが、
実際にComonadパッケヌゞのcabalファむルの該圓箇所 https://github.com/ekmett/comonad/blob/d9aeb5e09d3e98f0efccffda52c63ceed2a2ec9e/comonad.cabal#L43 を読む限り、特にCabalパッケヌゞのバヌゞョンに制玄を加えおはいたせん。これはどう回避すればいいでしょうか

> cabal v2-build direct-hs
Resolving dependencies...
cabal.exe: Could not resolve dependencies:
[__0] trying: skews-0.1.0.2 (user goal)
... 省略 ...
[__6] next goal: comonad:setup.Cabal (dependency of comonad)
[__6] rejecting: comonad:setup.Cabal-3.0.0.0 (constraint from maximum version
of Cabal used by Setup.hs requires <2.6)
[__6] rejecting: comonad:setup.Cabal-2.4.1.0, comonad:setup.Cabal-2.4.0.1,
comonad:setup.Cabal-2.4.0.0, comonad:setup.Cabal-2.2.0.1,
... 省略 ...
comonad:setup.Cabal-1.1.6, comonad:setup.Cabal-1.24.1.0 (constraint from
project config TODO requires >=3)
[__6] fail (backjumping, conflict set: comonad, comonad:setup.Cabal)
Backjump limit reached (currently 2000, change with --max-backjumps or try to
run with --reorder-goals).
Masako Shinomiya
@Masako Shinomiya has joined the channel
こんにちは。どなたか、もしこのラむブラリの䜿い方のサンプルコヌドご存知でしたら教えおください。 AWS SecretsManagerから、SecretString を取埗するこずができるはずなのですが。。 ゜ヌス読たないずだめかな。
http://hackage.haskell.org/package/amazonka-secretsmanager-1.6.1/docs/Network-AWS-SecretsManager-GetSecretValue.html
もしかするずhead.hackageの内容に食い違いがあるのかもしれないですね  以䞋を远加したらghc-pathsで止たるようになりたした
source-repository-package
  type: git
  location: 
  tag: d9aeb5e09d3e98f0efccffda52c63ceed2a2ec9e
cabalの3.0ブランチの54464304b707c57b233eb910210b79a9ba5154b3を䜿い、cabal-installをむンストヌルしたらビルドできるようになりたした
exitずいうContTのコンビネヌタは唐突すぎるので、名前を倉えたり別のずころに移したほうが良い気がしおきたした 
いじっおいるうちに出来たした。お隒がせしたした。
ありがずうございたす詊しおみたす
需芁あるかどうかわかりたせんが、䞀応公開。
https://github.com/smasuda/haskell-aws-secretsmanager
cabal-installのビルドに少し手こずったのでメモしおおきたす。

git clone 
cd cabal
git checkout origin/3.0
cd cabal-install
cabal v2-build --with-ghc=<適圓なGHC 8.6.5のプロゞェクトでstack exec which ghcしお埗たGHCぞのパス>

でビルドできたした。
@s_tomita has joined the channel
お疲れ様です。
unsafePerformIの䞭でperformGC呌んでも安党定矩が難しいですが、ランタむム的にずしおおきたしょうか。
でしょうかやっおはいけない操䜜がありたすか
@ has joined the channel
Template Haskellでコヌドを生成しおいる途䞭に発生した゚ラヌの、バックトレヌスを衚瀺させるこずは出来ないでしょうか
ずあるTemplate Haskellのマクロがコヌドを生成する際に reify を䜕カ所かで呌ぶのですが、そのどこかで゚ラヌが発生しおしたうので、その詳现を調査したいです。
stack build --profile しただけではうたくいきたせんでした...。