Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 将算法重构为计算表达式?_Algorithm_F#_Functional Programming_Computation Expression - Fatal编程技术网

Algorithm 将算法重构为计算表达式?

Algorithm 将算法重构为计算表达式?,algorithm,f#,functional-programming,computation-expression,Algorithm,F#,Functional Programming,Computation Expression,这个问题为那些还没有完成的人提供了破坏者。我写了一个关于这个问题的答案,这是必须的,所以我开始做一个更通用、更实用的答案。我成功了,但现在正试图找出如何将其重构为计算表达式或使用计算表达式,对此我感到无可救药的困惑。下面详细描述了这个问题,但要点是,您正在尝试建立一个数字链,当按顺序排列时,它会在所有相邻的对之间显示一个属性。链的候选项都来自不同的数字池,这意味着蛮力算法必须聪明,以避免搜索所有可能的排列 我的猜测是,在包含计算表达式时,会以某种方式将搜索算法变成一个单子,它会继续添加到解决方案

这个问题为那些还没有完成的人提供了破坏者。我写了一个关于这个问题的答案,这是必须的,所以我开始做一个更通用、更实用的答案。我成功了,但现在正试图找出如何将其重构为计算表达式或使用计算表达式,对此我感到无可救药的困惑。下面详细描述了这个问题,但要点是,您正在尝试建立一个数字链,当按顺序排列时,它会在所有相邻的对之间显示一个属性。链的候选项都来自不同的数字池,这意味着蛮力算法必须聪明,以避免搜索所有可能的排列

我的猜测是,在包含计算表达式时,会以某种方式将搜索算法变成一个单子,它会继续添加到解决方案或转储空列表。但我不完全确定

(*
Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are
all figurate (polygonal) numbers and are generated by the following formulae:

Triangle        P3,n=n(n+1)/2       1, 3, 6, 10, 15, ...
Square          P4,n=n2             1, 4, 9, 16, 25, ...
Pentagonal      P5,n=n(3n−1)/2      1, 5, 12, 22, 35, ...
Hexagonal       P6,n=n(2n−1)        1, 6, 15, 28, 45, ...
Heptagonal      P7,n=n(5n−3)/2      1, 7, 18, 34, 55, ...
Octagonal       P8,n=n(3n−2)        1, 8, 21, 40, 65, ...

The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three 
interesting properties.

The set is cyclic, in that the last two digits of each number is the first two 
digits of the next number (including the last number with the first).
Each polygonal type: triangle (P3,127=8128), square (P4,91=8281), and pentagonal 
(P5,44=2882), is represented by a different number in the set.
This is the only set of 4-digit numbers with this property.

Find the sum of the only ordered set of six cyclic 4-digit numbers for which 
each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and 
octagonal, is represented by a different number in the set.
*)


let rec distribute e = function
    | [] -> [[e]]
    | x::xs' as xs -> (e::xs)::[for xs in distribute e xs' -> x::xs]

// Return a list of all permutations of a list
let rec permute = function
    | [] -> [[]]
    | e::xs -> List.collect (distribute e) (permute xs)

// Return a list rotated until it's minimum element is the head
let canonicalCyclicPermutation (permutationList : 'a list) = 
    let min = Seq.min permutationList
    let rec loop ourList = 
        match ourList with
        | head :: tail when head = min -> ourList
        | head :: tail -> loop (tail @ [head])
    loop permutationList

// Return a list of all permutations of a list that is rotationally/cylically unique
let permutateCycUniq seedList = 
    permute seedList
    |> List.distinctBy canonicalCyclicPermutation

// Generate a sequence of all s-gonal numbers
let polygonalGenerator s = 
    Seq.initInfinite (fun idx -> ((pown (idx+1) 2) * (s-2) - (idx+1)*(s-4))/2)

// Generate a sequence of s-gonal numbers relevant for our exercise
let polygonalCandidates s = 
    s
    |> polygonalGenerator
    |> Seq.skipWhile (fun x -> x <= 999)
    |> Seq.takeWhile (fun x -> x <= 9999)
    |> Seq.cache

// Create the polygonal numbers as a list not seq
let polygonalCandidatesL s = 
    polygonalCandidates s
    |> Seq.toList

// Returns true if the last digits of first input are first digits in last input
let sharesDigits xxvv vvyy = 
    (xxvv / 100) = (vvyy % 100)

// Returns true if a sequence is cyclical
let isCyclical intSeq = 
    (Seq.append intSeq (Seq.take 1 intSeq))
    |> Seq.pairwise 
    |> Seq.fold (fun acc (num1,num2) -> acc && (sharesDigits num1 num2)) true

// Returns an empty list if the candidate number does not share digits
// with the list head, otherwise returns the list with the candidate at the head
let addCandidateToSolution (solution : int list) (number : int) =
    match solution with
    | (head::tail) when sharesDigits number head -> number::head::tail
    | _ -> []

// Returns a sequence of all valid solutions generated by trying to add
// a sequence of candidates to all solutions in a sequence
let addCandidatesToSolution (solutions : int list seq) (candidates : int seq) =
    Seq.collect (fun solution -> 
                 Seq.map (fun candidate -> 
                          addCandidateToSolution solution candidate)
                          candidates
                |> Seq.filter (not << List.isEmpty)) 
              solutions

// Given a list of side lengths, we return a sequence of cyclical solutions
// from the polygonal number families in the order they appear in the list
let generateSolutionsFromPolygonalFamilies (seedList : int list) = 
    let solutionSeeds = 
        seedList 
        |> List.head
        |> polygonalCandidates
        |> Seq.map (fun x -> [x])

    let solutions = 
        Seq.fold (fun acc elem -> (addCandidatesToSolution acc elem)) 
                 solutionSeeds 
                 ((List.tail seedList) |> List.map polygonalCandidatesL)
        |> Seq.filter isCyclical
    solutions

// Find all cyclical sequences from a list of polygonal number families
let FindSolutionsFromFamilies intList = 
    intList
    |> permutateCycUniq
    |> Seq.collect generateSolutionsFromPolygonalFamilies
    |> Seq.toList

// Given in the problem
let sampleAnswer = FindSolutionsFromFamilies [3;4;5]

// The set of answers that answers the problem
#time
let problemAnswer = FindSolutionsFromFamilies [3 .. 8]
#time // 0.09s wow!
(*
三角形、正方形、五边形、六边形、七边形和八角形的数字是
所有数字(多边形)和由以下公式生成:
三角形P3,n=n(n+1)/21,3,6,10,15。。。
平方P4,n=n2 1,4,9,16,25。。。
五边形P5,n=n(3n−1)/2      1, 5, 12, 22, 35, ...
六角P6,n=n(2n−1)        1, 6, 15, 28, 45, ...
七边形P7,n=n(5n−3)/2      1, 7, 18, 34, 55, ...
八角形P8,n=n(3n−2)        1, 8, 21, 40, 65, ...
三个4位数字的有序集合:81288281,有三个
有趣的属性。
该集合是循环的,因为每个数字的最后两位是前两位
下一个数字的位数(包括最后一个数字和第一个数字)。
每个多边形类型:三角形(P3127=8128)、正方形(P4,91=8281)和五边形
(P5,44=2882),由集合中的不同数字表示。
这是唯一一组具有此属性的4位数字。
求六个循环4位数字的唯一有序集的和
每种多边形类型:三角形、正方形、五边形、六边形、七边形和三角形
八角形,由集合中的不同数字表示。
*)
让rec分配e=函数
|[]->[[e]]
|x::xs'作为xs->(e::xs)::[对于分布式e xs'->x::xs中的xs]
//返回列表的所有排列的列表
让rec permute=函数
| [] -> [[]]
|e::xs->List.collect(分发e)(permute xs)
//返回一个旋转的列表,直到它的最小元素是head
让CanonicalCycleCPermutation(排列列表:'a列表)=
设min=Seq.min置换列表
让rec循环我们的列表=
将我们的名单与
|head::head=min时的tail->ourList
|head::tail->loop(tail@[head])
循环置换表
//返回在旋转/循环上唯一的列表的所有排列的列表
让permutateCycUniq种子列表=
排列种子表
|>List.distinctBy CanonicalCycleCPermutation
//生成所有s形数的序列
设多边形生成器s=
Seq.initInfinite(fun idx->((pown(idx+1)2)*(s-2)-(idx+1)*(s-4))/2)
//生成一系列与我们的运动相关的s形数字
让多边形标注s=
s
|>多边形发生器
|>Seq.skipWhile(乐趣x->x Seq.takeWhile(乐趣x->x Seq.cache
//将多边形编号创建为列表而不是序列
设polygonalCandidatesL s=
黄精
|>序号:toList
//如果第一个输入的最后一位是最后一个输入的第一位,则返回true
让共享数字xxvvyy=
(xxvv/100)=(vvyy%100)
//如果序列是循环的,则返回true
设isCyclical intSeq=
(序号附加intSeq(序号取1 intSeq))
|>顺序:成对
|>Seq.fold(fun acc(num1,num2)->acc&&(sharesDigits num1,num2))正确
//如果候选号码不共享数字,则返回空列表
//使用列表头,否则返回列表,候选人位于列表头
let addCandidateToSolution(解决方案:int列表)(编号:int)=
匹配解决方案
|(head::tail)当共享数字head->number::head::tail时
| _ -> []
//返回通过尝试添加生成的所有有效解决方案的序列
//序列中所有解的候选序列
让我们添加候选测试解决方案(解决方案:int list seq)(候选项:int seq)=
Seq.collect(有趣的解决方案->
Seq.map(有趣的候选人->
添加候选解决方案(候选解决方案)
候选人
|>序号过滤器(非列表标题
|>多角形裙带菜
|>Seq.map(乐趣x->[x])
设解=
序号折叠(趣味acc要素->(添加候选测试解决方案acc要素))
溶液种子
((List.tail seedList)|>List.map polygonalCandidatesL)
|>顺序过滤器是循环的
解决
//从多边形数族列表中查找所有循环序列
让FindSolutionsFromFamilies intList=
内部列表
|>置换细胞
|>Seq.collect GenerateSolutions from PolygonalFamilies
|>序号:toList
//在问题中给出
让sampleAnswer=FindSolutionsFromFamilies[3;4;5]
//回答问题的答案集
#时间
let problemAnswer=从族中找到解决方案[3..8]
#时间//0.09s哇!

虽然一开始我持怀疑态度,但我不得不承认,这个问题背后的思想是相当合理的,而实际的实现似乎相当难以捉摸。由于必须提供
成员Bind:ma:'a list*f:('a->'b list)的等效一元签名->“b列表”
对于给定的数据结构,很自然地会使用F列表并使用其相应的高阶函数
list.collect

type ListBuilder () =
    member __.Return x = [x]
    member __.Bind(ma, f) = List.collect f ma

let myList a b = ListBuilder () {
    let! x = a
    let! y = b
    return x, y } 

myList [1..2] [3..4]    // [(1, 3); (1, 4); (2, 3); (2, 4)]
这个最小但光滑的笛卡尔积并没有让我们走得很远。我们需要使执行链有条件,需要一个额外的成员,
Zero
。显然,固定算术是这种方法的一个主要缺点

type MyListBuilder () =
    member __.Zero _ = []
    member __.Return x = [x]
    member __.Bind(ma, f) = List.collect f ma

let myListXY cmp a b c = MyListBuilder () {
    let! r = a
    let! s = b
    if cmp r s then 
        let! t = c
        if cmp s t then 
            if cmp t r then 
                return r, s, t } 

let T n k = if n < 2 then 0 else ((n - 2) * k * k - (n - 4) * k) / 2

let figurate s min max =
    Seq.initInfinite ((+) 1)
    |> Seq.map (T s)
    |> Seq.takeWhile (fun n -> n < max)
    |> Seq.filter (fun n -> n >= min)
    |> Seq.toList

myListXY (fun x y -> x % 100 = y / 100)
    (figurate 3 1000 10000)
    (figurate 5 1000 10000)
    (figurate 4 1000 10000) // [(8128, 2882, 8281)]
键入MyListBuilder()=
成员_uz.Z