কার্যকরী প্রোগ্রামিং রাষ্ট্র থেকে মুক্তি পাবে না। এটি কেবল এটি স্পষ্ট করে তোলে! যদিও এটি সত্য যে মানচিত্রের মতো ফাংশনগুলি প্রায়শই "ভাগ করা" ডেটা স্ট্রাকচারকে "উদ্ঘাটন" করে দেয়, আপনি যা করতে চান তা যদি কোনও পুনঃব্যবহারযোগ্যতা অ্যালগরিদম লিখতে হয় তবে আপনি ইতিমধ্যে কোন নোডগুলি পরিদর্শন করেছেন সেটি ট্র্যাক করার বিষয়টি কেবল:
import qualified Data.Set as S
data Node = Node Int [Node] deriving (Show)
-- Receives a root node, returns a list of the node keyss visited in a depth-first search
dfs :: Node -> [Int]
dfs x = fst (dfs' (x, S.empty))
-- This worker function keeps track of a set of already-visited nodes to ignore.
dfs' :: (Node, S.Set Int) -> ([Int], S.Set Int)
dfs' (node@(Node k ns), s )
| k `S.member` s = ([], s)
| otherwise =
let (childtrees, s') = loopChildren ns (S.insert k s) in
(k:(concat childtrees), s')
--This function could probably be implemented as just a fold but Im lazy today...
loopChildren :: [Node] -> S.Set Int -> ([[Int]], S.Set Int)
loopChildren [] s = ([], s)
loopChildren (n:ns) s =
let (xs, s') = dfs' (n, s) in
let (xss, s'') = loopChildren ns s' in
(xs:xss, s'')
na = Node 1 [nb, nc, nd]
nb = Node 2 [ne]
nc = Node 3 [ne, nf]
nd = Node 4 [nf]
ne = Node 5 [ng]
nf = Node 6 []
ng = Node 7 []
main = print $ dfs na -- [1,2,5,7,3,6,4]
এখন, আমি অবশ্যই স্বীকার করে নিতে পারি যে হাতছাড়া হয়ে এই সমস্ত রাজ্যের খোঁজ রাখা বেশ বিরক্তিকর এবং ত্রুটিযুক্ত প্রবণ (এটি 's এর পরিবর্তে' s 'ব্যবহার করা সহজ, একই s' কে একাধিক গণনায় পাস করা সহজ ...) । এখানেই সন্ন্যাসীরা এসেছেন: তারা এর আগে এমন কিছু সংযোজন করে না যা আপনি আগেই করতে পারেননি তবে তারা আপনাকে রাষ্ট্রের পরিবর্তনশীলকে পুরোপুরি স্পষ্টভাবে পাস করতে দেয় এবং ইন্টারফেসটি গ্যারান্টি দেয় যে এটি একক থ্রেডযুক্ত পদ্ধতিতে ঘটেছিল।
সম্পাদনা: আমি এখন যা করেছি তার আরও যুক্তি দেওয়ার চেষ্টা করব: প্রথমত, কেবল পুনরায় ব্যবহারযোগ্যতার জন্য পরীক্ষা করার পরিবর্তে আমি গভীরতার প্রথম অনুসন্ধানে কোড দিয়েছিলাম। বাস্তবায়ন দেখতে অনেকটা একই রকম হবে তবে ডিবাগিংটি আরও ভাল দেখাচ্ছে।
রাষ্ট্রীয় ভাষায়, ডিএফএস এই জাতীয় চেহারা দেখায়:
visited = set() #mutable state
visitlist = [] #mutable state
def dfs(node):
if isMember(node, visited):
//do nothing
else:
visited[node.key] = true
visitlist.append(node.key)
for child in node.children:
dfs(child)
পরিবর্তনশীল অবস্থা থেকে মুক্তি পাওয়ার জন্য এখন আমাদের একটি উপায় খুঁজে বের করা উচিত। প্রথমে আমরা "ভিজিটলিস্ট" ভেরিয়েবলকে ডিএফএসের মাধ্যমে ফিরিয়ে আনব যা শূন্য করার পরিবর্তে:
visited = set() #mutable state
def dfs(node):
if isMember(node, visited):
return []
else:
visited[node.key] = true
return [node.key] + concat(map(dfs, node.children))
এবং এখন জটিল অংশটি আসে: "ভিজিট করা" ভেরিয়েবল থেকে মুক্তি পাওয়া। মূল কৌশলটি এমন একটি কনভেনশন ব্যবহার করা হয় যেখানে আমরা প্রয়োজনীয় ক্রিয়াকলাপগুলিতে অতিরিক্ত প্যারামিটার হিসাবে রাজ্যটি পাস করি এবং সেগুলি সংশোধন করতে চাইলে এই ফাংশনগুলি রাজ্যের নতুন সংস্করণকে অতিরিক্ত রিটার্ন মান হিসাবে ফিরিয়ে দেয়।
let increment_state s = s+1 in
let extract_state s = (s, 0) in
let s0 = 0 in
let s1 = increment_state s0 in
let s2 = increment_state s1 in
let (x, s3) = extract_state s2 in
-- and so on...
ডিএফএসে এই প্যাটার্নটি প্রয়োগ করতে, অতিরিক্ত প্যারামিটার হিসাবে "পরিদর্শন করা" সেটটি পেতে এবং অতিরিক্ত পরিমার্জনের মান হিসাবে "পরিদর্শন করা" এর আপডেট হওয়া সংস্করণটি ফিরিয়ে আনতে আমাদের এটিকে পরিবর্তন করতে হবে। অতিরিক্তভাবে, আমাদের কোডটি আবারও লিখতে হবে যাতে আমরা সর্বদা "দেখা" অ্যারের "অতি সাম্প্রতিক" সংস্করণটি এগিয়ে দিচ্ছি:
def dfs(node, visited1):
if isMember(node, visited1):
return ([], visited1) #return the old state because we dont want to change it
else:
curr_visited = insert(node.key, visited1) #immutable update, with a new variable for the new value
childtrees = []
for child in node.children:
(ct, curr_visited) = dfs(child, curr_visited)
child_trees.append(ct)
return ([node.key] + concat(childTrees), curr_visited)
হাস্কেল সংস্করণটি আমি এখানে যা করেছি তা বেশ কিছু করে, কেবল এটি পুরোপুরি চলে এবং পরিবর্তিত "curr_visited" এবং "শিশুসন্তান" ভেরিয়েবলের পরিবর্তে একটি অভ্যন্তরীণ পুনরাবৃত্তির ফাংশন ব্যবহার করে।
মোনাডদের ক্ষেত্রে, তারা মূলত যা সম্পাদন করে তা হস্তান্তর করে আপনার হাতের সাহায্যে জোর করে পরিবর্তে "curr_visited" চারপাশে পাস করছে। এটি কেবল কোড থেকে বিশৃঙ্খলা দূর করে না, বরং এটি আপনাকে ভুল করা থেকেও বাধা দেয় যেমন ফোরকিং স্টেট (একই "দেখা" কে রাষ্ট্রের শৃঙ্খলার পরিবর্তে দুটি পরবর্তী কলগুলিতে সেট করা)।