使用一组默认值(elm或haskell)初始化模块

使用一组默认值(elm或haskell)初始化模块,haskell,elm,Haskell,Elm,假设我们有一个模块,负责向Flickr发出api请求。我不想将api键硬编码到Flickr模块中。Api密钥可以通过ajax请求获得 目前,Flickr模块中的每个函数都接受apiKey作为其参数。但这并不是说api密钥的传递很酷。有什么简单的方法可以解决这个问题吗?或者,是否可以在模块之间共享一些值而不传递每个函数 module Flickr where searchPhotos : String -> String -> ... searchPhotos apiKey quer

假设我们有一个模块,负责向Flickr发出api请求。我不想将api键硬编码到Flickr模块中。Api密钥可以通过ajax请求获得

目前,Flickr模块中的每个函数都接受apiKey作为其参数。但这并不是说api密钥的传递很酷。有什么简单的方法可以解决这个问题吗?或者,是否可以在模块之间共享一些值而不传递每个函数

module Flickr where

searchPhotos : String -> String -> ...
searchPhotos apiKey query = ...

getPhotoInfo : String -> String -> ...
getPhotoInfo apiKey photoId = ...

anotherOne : String -> ...
anotherOne apiKey = ...

更新:到目前为止,我尝试的是部分应用函数。我在最后放了一个类似apiKey的参数。但是现在我必须把这个函数到处传递,还有其他想法吗

makeFlickrRequest : (String -> String -> a) -> a
makeFlickrRequest flickrMethod = flickrMethod "myApikey" "mySecret"

photosSearch : String -> String -> String -> ...
photosSearch query apiKey secret =
    makeHTTPCallhere ...

-- Usage:
makeFlickrRequest (photosSearch "haskell")
使用,您可以隐藏所有函数的公共“环境”(API键)。下面是一个简单的例子:

首先,

import Control.Monad.Reader
然后,使用一些类型别名来帮助可读性。这里值得注意的是
flickrequest a
部分-它表示返回
a
类型值的flickr请求:

type APIKey = String
type Photo = String
type PhotoInfo = String

type FlickrRequest a = Reader APIKey a
以下是搜索照片和获取某些照片信息的两个虚拟实现:

searchPhotos :: String -> FlickrRequest [Photo]
searchPhotos query = do
    apiKey <- ask
    return ["<Photo for query " ++ query ++ " (api key " ++ apiKey ++ ")>"]

getPhotoInfo :: Photo -> FlickrRequest PhotoInfo
getPhotoInfo photo = do
    apiKey <- ask
    return $ "This is the photo information for photo " ++ photo ++ " (" ++ apiKey ++ ")"
我们首先调用
searchPhotos
,然后将
getPhotoInfo
应用于所有找到的照片。请注意,API键是如何不可见的,它是隐式传递的

最后,要运行整个程序,可以使用
runReader
函数。差不多

main :: IO ()
main = do
    let myAPIKey = "someAPIKey"
    print (runReader allPhotoInfos myAPIKey)

为了解释我的评论,我的意思是将apikey应用于每个函数,如下所示:


Frerich Raabe的解决方案对Haskell非常有效,但不幸的是,我们没有Elm中的
do
符号或等效的读卡器Monad

但是,我们有一些端口,可以在从Javascript初始化Elm模块时使用这些端口提供配置数据

例如,您可以在Elm中定义一个名为
apiKey
的端口。因为端口的值来自javascript,所以我们只定义函数签名,而不是主体:

端口apiKey:字符串
在启动Elm模块的HTML/javascript文件中,可以传递包含初始端口值的第二个参数,如下所示:


var app=Elm.全屏(Elm.Main{
apiKey:“我的apiKey”
});

现在,在整个Elm代码中,有一个名为
apiKey
的常量函数始终可用。您永远不需要将其作为参数传递给其他函数。

这听起来像是的一个用例。您可以为所有函数部分应用apikey,这就是您需要的吗?@DanielSanchez实际上我已经尝试过了(更新的问题)。但现在我必须将makeFlickrRequest函数传递给每个需要发出请求的模块。我在寻找一个更好的选择:)制作这个函数的
版本,我不是一个专业的haskeller,我只是在说我想说的,也许读者monad是一个更容易理解的方法。隐式传递配置信息的另一个好方法是使用
反射
库。调用任何函数时,您都可以将配置具体化,然后使用
reflect
在需要的地方将其取回。美观大方,我必须进入monads,谢谢。谢谢您的详细解释。我试图避免使用单子来保持简单。但似乎最简单的处理方法是使用ReaderMonad。Elm没有do注释不幸的是:(如果有人没有提出替代解决方案,我会接受你的答案。
main :: IO ()
main = do
    let myAPIKey = "someAPIKey"
    print (runReader allPhotoInfos myAPIKey)
type ApiKey = String

apikey::ApiKey
apikey = "foo"


f1 :: ApiKey -> String -> String
f1 "foo" _  = "1"
f1 _ s =  s

f2 :: ApiKey -> String -> String
f2 "foo" _  = "2"
f2 _ s =  s

f1', f2':: (String -> String)
[f1', f2'] = map (\x-> x apikey) [f1, f2]

main = do
    putStrLn $ f1 "asdf" "2"
    putStrLn $ f1' "2"