2016-01-08 75 views
3

假設我們有一個模塊,負責將012請求發送到Flickr。我不想將api密鑰硬編碼到Flickr模塊中。 Api鍵可以通過ajax請求獲取。使用默認設置初始化一個模塊(elm或haskell)

對於現在的Flickr的模塊中的每個函數接受apiKey作爲其參數。但是,它並不是那種令人期待的關鍵。有沒有簡單的方法來解決這個問題?或者是否有可能在模塊之間共享某些值而不傳遞每一個函數。

module Flickr where 

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

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

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

UPDATE:我有什麼到目前爲止已經試過部分應用功能。最後,我把apiKey像參數一樣。但是現在我必須將這個功能全部通過,還有其他想法嗎?

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

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

-- Usage: 
makeFlickrRequest (photosSearch "haskell") 
+0

這聽起來像['reader monad']的用例(http://hackage.haskell.org/package/mtl-1.1.0.1/docs/Control-Monad-Reader.html)。 –

+0

你可以偏愛應用所有你的功能的apikey,這是你需要的嗎? – Netwave

+0

@DanielSanchez其實我試過(更新的問題)。但是現在我必須將makeFlickrRequest函數傳遞給需要發出請求的每個模塊。我正在尋找一個更好的選擇:) –

回答

4

Frerich拉貝的解決方案Haskell的偉大工程,但很遺憾,我們沒有豪華在Elm或Reader Monad等價物中使用do表示法。

但是,我們有港口,我們可以初始化從Javascript榆樹模塊時使用,以提供配置數據。

例如,你可以有一個口叫榆樹定義apiKey。由於港口的價值來自於JavaScript中,我們只定義函數簽名,而不是身體:

port apiKey : String 

在HTML /在榆樹模塊被啓動的JavaScript文件,你可以傳遞一個包含初始第二個參數端口值是這樣的:現在

<script> 
    var app = Elm.fullscreen(Elm.Main, { 
    apiKey: "myApiKey" 
    }); 
</script> 

,整個榆樹代碼,您有一個稱爲apiKey總是可用的常數函數。你永遠不需要將它作爲參數傳遞給其他函數。

6

隨着reader monad,你可以隱藏所有的函數(API密鑰)的距離常見的「環境」。這裏有一個簡單的例子:

首先,

import Control.Monad.Reader 

然後,某些類型的別名,以幫助可讀性。有什麼值得一提的這裏是FlickrRequest 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 ++ ")" 

請注意,API密鑰是通過FlickrRequest閱讀器隱式傳遞的。在功能中,您可以使用ask訪問該環境(您可以「讀取」環境)。這樣做的好處來組合這些功能,這都在同一個環境中操作,e.g時:

-- This could be just `searchPhotos "*" >>= mapM getPhotoInfo` but I don't 
-- want to obscure things unnecessarily. 
allPhotoInfos :: FlickrRequest [PhotoInfo] 
allPhotoInfos = do 
    photos <- searchPhotos "*" 
    sequence (map getPhotoInfo photos) 

我們首先調用searchPhotos,然後應用getPhotoInfo所有找到的照片英寸注意API密鑰是如何看不見的,它隱含地傳遞了!

最後,運行整個事情,你可以使用runReader功能。喜歡的東西

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

美麗而優雅,必須讓自己進入monads,感謝這一點。 – Netwave

+0

感謝您的詳細解釋。我試圖避免使用monads來保持簡單。但似乎最簡單的方法是使用reader monad。不幸的是,Elm沒有''''''''''notaion :(如果有人沒有提出替代解決方案,我會接受你的回答。 –

0

只是爲了說明我的意見,我的意思是apikey適用於每一個功能,因爲這example

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" 
相關問題