Thực hiện các mô hình lập trình chức năng


21

Công ty của bạn mới bắt đầu thực hiện một dự án và lần đầu tiên bạn quyết định sử dụng kiểu mã lập trình chức năng. Tuy nhiên, sếp của bạn thực sự khác biệt và không muốn sử dụng các chức năng tích hợp sẵn và yêu cầu bạn phải tự thực hiện các chức năng chính. Đặc biệt bạn cần phải viết các chức năng: Map, Nest, Apply, Range, FoldTablebằng một ngôn ngữ vào sự lựa chọn của bạn. Sếp là một người thực sự bận rộn và anh ấy muốn có các chương trình càng ngắn càng tốt, vì vậy anh ấy không lãng phí thời gian để đọc. Anh ấy cũng không muốn bạn sử dụng các vòng lặp, do đó bạn sẽ giảm 10% số lượng byte vì không sử dụng các vòng lặp.

Các yêu cầu chi tiết của các chức năng dưới đây:

Bản đồ

Các Mapchức năng có hai tham số: flistnơi flà một chức năng và listlà một danh sách các giá trị. Nó sẽ trả về fáp dụng cho từng yếu tố của list. Do đó, nó sẽ hoạt động như vậy:

Map(f,{a,b,c})

trả lại

{ f(a), f(b), f(c) }

Map(f, {{a,b},{b,c}})

trả lại

{ f({a,b}), f({b,c})}

Yến

Các Nestchức năng có ba thông số cũng như: f, arg, timesnơi flà một chức năng, arglà tranh luận bắt đầu của nó, và timeslà bao nhiêu lần so với chức năng được áp dụng. Nó sẽ trả về một biểu thức với thời gian fáp dụng timescho arg. Do đó, nó sẽ hoạt động như vậy:

Nest(f, x, 3)

trả lại

f(f(f(x)))

Nest(f, {a,b}, 3)

trả lại

f(f(f({a,b})))

Ứng dụng

Các Applychức năng có hai tham số: fargsnơi flà một chức năng và argsmột danh sách. Nó nên áp dụng fcho args. Vì thế:

Apply(f, {a,b,c})

trả lại

f(a,b,c)

Phạm vi

Các Rangechức năng mất một số nguyên rvà xuất ra các số nguyên lên đến con số đó. Vì thế:

Range(5)

trả lại

{ 1, 2, 3, 4, 5}

Gập lại

Các Foldchức năng có ba thông số f, arg, othersnơi flà một chức năng, arglà tham số đơn giản, và othersmột danh sách. Nó sẽ hoạt động như vậy:

Fold(f, x, {a, b, c, d})

trả lại

f(f(f(f(x,a),b),c),d)

Bàn

Các hàm bảng nên có một hàm fvà một tham số được gọi iteratorở dạng: {iMin, iMax}where iMiniMaxlà các số nguyên. Bạn nên áp dụng ftrong phạm vi được chỉ định. Vì thế:

Table(f, {0, 5})

trả lại

{f(0), f(1), f(2), f(3), f(4), f(5)}

Tôi đã sử dụng định nghĩa của các hàm này từ trang lập trình chức năng Mathicala , vì vậy hãy đến đó nếu bạn cần thêm hướng dẫn. Lưu ý rằng bạn sẽ không cần phải thực hiện tất cả phiên bản của các chức năng được hiển thị trong trang đó, mà chỉ những chức năng được viết trong bài đăng này.

Lỗ hổng tiêu chuẩn không được phép như bình thường.

Trong trường hợp ngôn ngữ của bạn không cho phép các chức năng được chuyển qua làm đối số, bạn cần triển khai khả năng này và thêm nó vào câu trả lời của mình. Tuy nhiên, tổng số byte của thao tác này sẽ không được thêm vào tổng số.

Đây là mã golf nên mã ngắn nhất sẽ thắng. Chúc may mắn!!!


Điều này thật tuyệt! +1 Tuy nhiên, tôi không thực sự hiểu làm thế nào Tablehoạt động ở đây. Là ví dụ của bạn được cho là Table(f, {x, 0, 5})? Tôi cũng không có mục đích xgì cả, vì nó chỉ áp dụng chức năng cho phạm vi.
kirbyfan64sos

@ kirbyfan64sos Cảm ơn bạn! Vâng, đó là một lỗi đánh máy, tôi đã để lại x để làm tài liệu tham khảo cho
mathicala

Một câu hỏi nữa: làm thế nào để chúng ta đặt tên cho các chức năng? Chúng ta có phải đặt cho họ cùng tên chính xác không? Đơn thư?
kirbyfan64sos

@ kirbyfan64sos Vì là môn đánh gôn, tôi sẽ cho phép các tên chữ cái duy nhất, tuy nhiên trong câu trả lời của bạn, hãy đặt tiêu đề cho mỗi chức năng để chúng tôi biết đó là tên nào. Cũng không sử dụng các chữ cái va chạm.
WizardOfMenlo

Bạn có thể cụ thể hơn về những gì được coi là một vòng lặp?
xnor

Câu trả lời:


9

Haskell, nhiều byte trước đó đếm 127 * 0.9 = 114.3 byte

f#(a:b)=f a:f#b;f#x=x
(f&x)0=x;(f&x)i=f$f&x$i-1
i=id
r x=i%(1,x)
(g?x)(a:b)=g(g?x$b)a;(g?x)y=x
f%(a,b)|a>b=[]|1<2=f a:f%(a+1,b)

Không có vòng lặp, chỉ cần đệ quy.

#là bản đồ: (*2) # [1,2,3]->[2,4,6]

&là tổ: ((*2) & 3) 4->48

iđược áp dụng: i (*2) 7->14

rlà phạm vi: r 4->[1,2,3,4]

?là gấp: ((+) ? 0) [1,2,3,4]->10

%là bảng: (*2) % (2,4)->[4,6,8]

Theo yêu cầu một phiên bản không có ý kiến ​​với ý kiến. Lưu ý &?là các toán tử infix ternary, yêu cầu dấu ngoặc đơn bổ sung khi được gọi hoặc mẫu khớp.

f # (a:b) = f a : f#b        -- map on a list (a->head, b->tail) is f a in front of mapping f to b
f # x     = x                -- map on the empty list is the empty list
                             -- (non empty lists are caught in the line before) 

(f & x) 0 = x                -- nesting zero times is x
(f & x) i = f $ f&x $ i-1    -- nesting i times is f (nesting one time less)

i=id                         -- apply in Haskell is just the identity function 

r x = i % (1,x)              -- defined via the "table" of the identity function from 1 to x

(g ? x) (a:b) = g (g?x$b) a  -- folding g into a list (a->head, b->tail) is g applied to (folding g into b) and a
(g ? x) y     = x             -- folding the empty list is x
                             --  again, y must be the empty list, else it would have been handled by the previous line

f % (a,b)                    
  |a>b       = []                -- if iMin is greater than iMax, the table is empty
  |otherwise = f a : f%(a+1,b)   --  otherwise f a in front of the table with iMin increased by one

Cảm ơn @dfeuer và @Zgarb về một số gợi ý hữu ích


Tôi mới sử dụng haskell, nó có vẻ khá tốt, tuy nhiên bạn có thể vui lòng thêm một lời giải thích cho những gì bạn đang làm không?
WizardOfMenlo

1
@WizardOfMenlo: đã thêm một số nhận xét
nimi

Chỉ cần nhận ra rằng Haskell thanh lịch là như thế nào, thực sự tốt!
WizardOfMenlo

1
Bỏ qua danh sách vô hạn và hiệu quả m#q=reverse$f((:).m)[]q,. Đây là cùng độ dài với bạn, nhưng khó đọc hơn nhiều.
dfeuer

Bạn có thể rút ngắn !bằng cách đặt tên thay vì toán tử : i f=f.
dfeuer

5

Python 2, 305.1 byte (-10% 376 369 366 349 339 byte)

exec'e=eval;q=len;m=@,l:e("["+"f(l.pop()),"*q(l)+"][::-1]");n=@,x,l:e("f("*l+"*x"+")"*l);r=@:e("r(f-1)+"*(f>1)+"[f]");a=@,a:e("f(a["+`r(q(a))`[1:-1]$",","-1],a[")+"-1])");f=@,x,l:e("f("*q(l)+"x,["+`r(q(l))`[1:-1]$",","-1]),l[")+"-1])");t=@,n,x:e("[f("+`r(x)[n-1:]`$",","),f(")[1:-1]+")]")'.replace("@","lambda f").replace("$",".replace(")

Khi mở rộng, tương đương với:

e=eval;q=len
m=lambda f,l:e("["+"f(l.pop()),"*q(l)+"][::-1]")
n=lambda f,x,l:e("f("*l+"*x"+")"*l)
r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
a=lambda f,a:e("f(a["+`r(q(a))`[1:-1].replace(",","-1],a[")+"-1])")
f=lambda f,x,l:e("f("*q(l)+"x,["+`r(q(l))`[1:-1].replace(",","-1]),l[")+"-1])")
t=lambda f,n,x:e("[f("+`r(x)[n-1:]`.replace(",","),f(")[1:-1]+")]")

Không có vòng lặp!

Chà, nó làm rất nhiều việc evalvà nếu sếp của bạn không thể đứng vòng, thì họ sẽ ghét eval. Nhưng, họ sẽ phải chịu đựng nó

Một cách để làm rangetrong lambda được đánh giá cao vì vậy tôi không phải thực hiện bất kỳ chức năng nào (Shudder.).

Giải thích:

  • m=lambda f,l:eval("["+"f(l.pop()),"*len(l)+"][::-1]")
    • Tạo một chuỗi bật các phần tử từ danh sách, bọc nó thành một danh sách, đảo ngược nó và cuối cùng là đánh bại nó!
  • n=lambda f,x,l:eval("f("*l+"*x"+")"*l)
    • Tự tạo chuỗi với lồng và eval nó!
  • r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
    • Tạo một chuỗi mà khi evaled, trả về [0]hoặc sử dụng đệ quy để có được kết quả trước đó và thêm chỉ mục hiện tại vào danh sách. Đánh bại nó
  • a=lambda f,a:eval("f(a["+r (len (a))[1:-1].replace(",","-1],a[")+"-1])")
    • Sử dụng hàm phạm vi để lấy các chỉ mục 1-len (danh sách). Thay thế dấu phẩy trong danh sách được xâu chuỗi bằng cách lấy chỉ mục chính xác của danh sách a. Đánh giá nó!
  • f=lambda f,x,l:eval("f("*len(l)+"x,["+r (len (l))[1:-1].replace(",","-1]),l[")+"-1])")
    • Tương tự như áp dụng ngoại trừ thay thế dấu phẩy bằng dấu ngoặc đóng, dấu phẩy và bắt đầu chỉ mục danh sách.
  • t=lambda f,n,x:eval("[f("+r (x) [n-1:].replace(",","),f(")[1:-1]+")]")
    • Tương tự như áp dụng và gấp trừ thay thế bằng kết thúc hàm và gọi hàm mới. Đánh giá nó!

Bản đồ, tổ, phạm vi, áp dụng, gấp, bảng.

Cảm ơn @Zgarb cho một lambda cho phạm vi!


Sếp của tôi sẽ để đầu tôi trên bàn của mình :) Bạn có thể thêm một lời giải thích ngắn gọn không?
WizardOfMenlo

Thế còn r=lambda i:[]if i<1 else r(i-1)+[i]? Không có vòng lặp, chỉ đệ quy.
Zgarb

1
Chắc chắn, tôi sẽ lấy nó ngay bây giờ nhưng ông chủ cần nhiều hơn evalđể chỉ cho họ cách các vòng lặp không quá tệ :)
Blue

Hà! Một phiên bản khác sử dụng e=eval:r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
Zgarb

bạn có thể thay đổi nó từ tiền thưởng 60% thành 10% không? Tôi đã sửa đổi đặc tả câu hỏi, để làm cho nó công bằng hơn
WizardOfMenlo

5

Javascript ES6, 197 * 0.9 = 177.3 byte

M=(f,l)=>F((a,b)=>[...a,f(b)],[],l)
N=(f,x,n)=>f(--n?N(f,x,n):x)
A=(f,l)=>f(...l)
R=n=>n--?[...R(n),n+1]:[]
F=(f,x,l,n=l.length)=>n--?f(F(f,x,l,n),l[n]):x
T=(f,i)=>([n,x]=i,M(q=>f(q+n-1),R(x-n+1)))

Bản đồ ( M=(f,l)=>F((a,b)=>[...a,f(b)],[],l)):

Sử dụng Fold để ghép các kết quả fáp dụng cho mọi thành viên lvào một danh sách trống. Việc sử dụng các chức năng tích hợp sẽ giảm điều này xuống M=(f,l)=>l.map(f)(không sử dụng vì nó có vẻ rẻ ...?).

Tổ ( N=(f,x,n)=>f(--n?N(f,x,n):x)):

Áp dụng fđệ quy cho đến khi ngiảm xuống 0.

Áp dụng ( A=(f,l)=>f(...l)):

Sử dụng ...toán tử lây lan ( ) để áp dụng llên f.

Phạm vi ( R=n=>n--?[...R(n),n+1]:[]):

Kết nnối cuộc gọi đệ quy của Phạm vi cho đến khi nđược giảm xuống 0.

Gấp ( F=(f,x,l,n=l.length)=>n--?f(F(f,x,l,n),l[n]):x):

Áp dụng các cuộc gọi đệ quy của Foldn'th yếu tố lđể fđến nđược giảm đến 0. Sử dụng built-in chức năng giảm này F=(f,x,l)=>l.reduce(f,x)(một lần nữa, có vẻ rẻ tiền ...).

Bảng ( T=(f,i)=>([n,x]=i,M(q=>f(q+n-1),R(x-n+1)))):

Đầu tiên, khởi tạo nxiMin và iMax bằng cách sử dụng hàm hủy ( [n,x]=i), sau đó sử dụng Phạm vi để xây dựng bảng giá trị từ iMin đến iMax. fsau đó được áp dụng trên bảng bằng Map và kết quả được trả về.


Bạn muốn biết triết lý của tôi? "Nếu nó rẻ, hãy mua nó." Nó không nói trong thông số kỹ thuật rằng bạn không thể sử dụng nội dung (chưa), vì vậy hãy sử dụng chúng!
Mama Fun Roll

4

Python 3, 218 byte

Phiên bản không thể đọc được:

exec("P!:[f(_)for _ in x];Y!,z:Y(f,f(x),z-1)if z else x;T!:f(*x);H!=0:(H(f-1)if~-f else[])+[f];O!,z:O(f,f(x,z[0]),z[1:])if z else x;N!:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]".replace("!","=lambda f,x"))

Phiên bản dễ đọc hơn:

P=lambda f,x:[f(_)for _ in x]
Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
T=lambda f,x:f(*x)
H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]

Đi qua nó một lambda tại một thời điểm:

Chức năng bản đồ P

P=lambda f,x:[f(_)for _ in x]
Chỉ là một trình vòng lặp đơn giản. Không có nhiều để nói ở đây.

Chức năng tổ Y

Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
Đệ quy cho đến khi zđạt 0, áp dụng fmọi lúc. Mệnh đề if ở cuối cảm thấy cồng kềnh; có lẽ có một cách tốt hơn để kết thúc đệ quy.

Áp dụng chức năng T

T=lambda f,x:f(*x)
Python có một toán tử mở rộng tốt để thực hiện tất cả các công việc nặng nhọc cho tôi.

Hàm phạm vi H

H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
Điều này khó hơn tôi mong đợi. Đã kết thúc bằng một cách tiếp cận đệ quy. Một lần nữa, cấu trúc if-other chiếm rất nhiều byte và tôi cảm thấy nó có thể được cải thiện. Tại sao nó có một hình nộm x=0, bạn hỏi? Vì vậy, khi tôi nén nó bằng exec, tôi có thể thay thế =lambda f,xchỉ =lambda f.

Chức năng gấp O

O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
Khá hạnh phúc với điều này. Chỉ bỏ qua phần tử đầu tiên của mảng mỗi lần nó lặp lại, cho đến khi không còn gì.

Chức năng bảng N

N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]
Điều này là khủng khiếp và tôi chắc chắn có chỗ để cải thiện. Đã thử sử dụng các chức năng phạm vi và bản đồ được xác định trước đây cho một map(f,range(x,y))loại xây dựng, nhưng không có nhiều thành công. Cuối cùng đã thực hiện một cách tiếp cận đệ quy khủng khiếp có chung một số chức năng phạm vi.

Tất cả các lambdas được gói trong execmột replaceđể rút ngắn đáng kể số byte.


Tôi chuẩn bị bình luận [f(_)for _ in x]có thể rút ngắn lại map(f,x), nhưng sau đó tôi nhớ thử thách là gì
Cyoce

4

Julia, 181 byte

Không có tiền thưởng cho tôi; Tôi đã sử dụng các vòng lặp tự do. Xin lỗi ông chủ, nhưng các vòng lặp ở Julia rất hiệu quả!

M(f,x)=[f(i...)for i=x]
N(f,x,n)=(for i=1:n x=f(x...)end;x)
A(f,x)=f(x...)
R(n)=(i=0;x={};while i<n push!(x,i+=1)end;x)
F(f,x,a)=(for b=a x=f(x,b)end;x)
T(f,i)=[f(j)for j=i[1]:i[2]]

Việc thêm các dấu chấm lửng sau một đối số vào một hàm sẽ phá vỡ một mảng, tuple hoặc những gì có trong các đối số hàm thông thường. Nếu không, hàm sẽ nghĩ rằng bạn đang cố gắng vượt qua một mảng (hoặc tuple, v.v.). Nó không có hiệu lực cho các đối số duy nhất.

Tên chức năng:

  • Bản đồ: M
  • Tổ: N
  • Ứng dụng: A
  • Phạm vi: R
  • Gập lại: F
  • Bàn: T

4

tinylisp , 325 * 0,9 = 292,5

Ngôn ngữ mới hơn câu hỏi, nhưng dù sao nó cũng sẽ không chiến thắng.

(d @(q(a a)))(d Q(q((l)(i l(c(@(q q)(h l))(Q(t l)))l))))(d A(q((f a)(v(c(q f)(Q a))))))(d M(q((f l)(i l(c(A f(@(h l)))(M f(t l)))l))))(d N(q((f a x)(i x(A f(@(N f a(s x 1))))a))))(d ,(q((m a b)(i(l b a)m(,(c b m)a(s b 1))))))(d R(q((a)(,()1 a))))(d T(q((f r)(M f(A ,(c()r))))))(d F(q((f a l)(i l(F f(A f(@ a(h l)))(t l))a))))

Xác định các hàm A(áp dụng), M(ánh xạ), N(lồng), R(phạm vi), T(bảng) và F(gấp), cùng với một vài hàm trợ giúp. Tmong đợi một danh sách hai số nguyên cho đối số thứ hai của nó.

Tinylisp thậm chí không có bất kỳ cấu trúc vòng lặp nào; tất cả mọi thứ được thực hiện bằng cách sử dụng đệ quy. Một vài trong số các chức năng này không được đệ quy đuôi , vì vậy nếu bạn gọi chúng trong danh sách lớn, chúng có thể sẽ thổi bay ngăn xếp cuộc gọi. Tất cả chúng có thể được thực hiện với đệ quy đuôi ... nhưng nó sẽ tốn nhiều byte hơn và đây là mã golf.

Đây là phiên bản mở rộng với khoảng trắng và từ thực cho tên, rất dễ đọc nếu bạn quen thuộc với Lisp. (Tôi đã đặt bí danh cho hầu hết các nội dung tinylisp ngoại trừ q(trích dẫn) và i(nếu).)

(d define d)
(define cons c)
(define car h)
(define cdr t)
(define subtract s)
(define less l)
(define eval v)

(define lambda
  (q (()
      (arglist expr)
      (list arglist expr))))

(define list (lambda args args))

(define quote-all
  (lambda (lyst)
    (i lyst
       (cons
         (list (q q) (car lyst))
         (quote-all (cdr lyst)))
       lyst)))

(define Apply
  (lambda (func arglist)
    (eval (cons (q func) (quote-all arglist)))))

(define Map
  (lambda (func lyst)
    (i lyst
       (cons
         (Apply func (list (car lyst)))
         (Map func (cdr lyst)))
       lyst)))

(define Nest
  (lambda (func arg times)
    (i times
       (Apply func
              (list (Nest func arg (subtract times 1))))
       arg)))

(define range*
  (lambda (accumulator a b)
    (i (less b a)
       accumulator
       (range* (cons b accumulator) a (subtract b 1)))))

(define Range
  (lambda (x)
    (range* 1 x)))

(define Table
  (lambda (func iterator)
    (Map func
         (Apply range* (cons () iterator)))))

(define Fold
  (lambda (func arg lyst)
    (i lyst
       (Fold func
             (Apply func (list arg (car lyst)))
             (cdr lyst))
       arg)))

Giải thích thêm có sẵn theo yêu cầu.

Sản lượng mẫu

Sử dụng môi trường REPL từ triển khai tham chiếu của tôi. Tôi đã sử dụng q(trích dẫn) cho hàm unary và s(trừ) làm hàm nhị phân cho các ví dụ này, cũng như hàm @(được xác định trong mã này) để trả về một danh sách các đối số của nó.

tl> [line of definitions goes here]
@
Q
A
M
N
,
R
T
F
tl> (A s (@ 10 7))
3
tl> (M q (@ 1 2 3 4))
((q 1) (q 2) (q 3) (q 4))
tl> (N q 123 4)
(q (q (q (q 123))))
tl> (R 5)
(1 2 3 4 5)
tl> (T q (@ 3 7))
((q 3) (q 4) (q 5) (q 6) (q 7))
tl> (F s 10 (@ 4 3 2))
1

2

Python 2.x: 450,6 byte (giảm 493 byte trước khi giảm giá 10%)

Câu trả lời đánh gôn:

y=len
z=lambda a,b:a.append(b)
_=lambda a:a if a is not None else[]
def M(a,b,c=None):
 c=_(c);d=y(b)
 if d:z(c,A(a,b[0]))
 return M(a,b[1:],c)if d else c
def N(a,b,c):d=A(a,b);return N(a,d,c-1)if c>1 else d
A=lambda a,b:a(*b)if type(b)is list else a(b)
def R(a,b=None):b=_(b);b.insert(0,a);return b if a<=1 else R(a-1,b)
def F(a,b,c):d=a(b,c[0]);return F(a,d,c[1:])if y(c)>1 else d
def T(a,b,c=None,d=None):
 if c is None:c=b[0];d=[]
 z(d,a(c));return T(a,b,c+1,d)if c<b[1]else d

Câu hỏi này rất vui. Tôi đã quyết định viết các hàm của mình mà không sử dụng các tương đương Python (mặc dù đó có thể là một lỗ hổng hợp lệ) và để viết các hàm như thể Python hỗ trợ đệ quy đuôi. Để thực hiện công việc này, tôi đã sử dụng rất nhiều tham số tùy chọn cho phép các cuộc gọi cần thiết vẫn hoạt động.

Dưới đây tôi có danh sách không ghi chú cho từng chức năng.

Apply:

A = lambda function, arguments: function(*arguments) if type(arguments) is list else function(arguments)

Map:

def M(function, arguments, result=None):
    result = result if result is not None else []
    length = len(arguments)
    if length != 0:
        result.append(A(function, arguments[0]))
    return M(function, arguments[1:], result) if length != 0 else result

Nest:

def N(function, arguments, times):
    result = A(function, arguments)
    return N(function, result, times - 1) if times > 1 else result

Lưu ý rằng hàm này yêu cầu thông qua functioncó thể đại diện cho nhiều đối số thay đổi. Một cách tiếp cận khác sẽ là thực thi rằng hàm luôn nhận được một danh sách duy nhất, nhưng điều đó sẽ yêu cầu các hàm được truyền có thể diễn giải các danh sách đối số. Dù sao cũng có giả định, nên tôi chọn cái phù hợp với phần còn lại của hệ thống hơn.

Range:

def R(ceiling, result=None):
    result = result if result is not None else []
    result.insert(0, ceiling)
    return result if ceiling <= 1 else R(ceiling - 1, result)

Fold:

def F(function, initial, rest):
    result = function(initial, rest[0])
    return F(function, result, rest[1:] if len(rest) > 1 else result

Table:

def T(function, iterator, current=None, result=None):
    if current is None:
        current = iterator[0]
        result = []
    result.append(function(current))
    return T(function, iterator, current + 1, result) if current < iterator[1] else result

Đây là đầu ra mẫu sử dụng các hàm trợ giúp sau:

square = lambda x: x * x
def add(*args):
    addTwo = lambda a, b: a + b
    if len(args) == 1 and type(args[0]) is list:
        return F(addTwo, 0, args[0])
    else:
        return F(addTwo, 0, args)

>>> M(square, R(10))
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> M(add, [R(i) for i in R(10)])
[1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
>>> T(square, [0, 10])
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> N(square, 2, 4)
65536
>>> N(lambda *args: F(lambda a, b: a * b, 1, args) if len(args) > 1 else str(args[0]) + 'a', R(5), 10)
'120aaaaaaaaa'

Wow, trông thực sự tốt!
WizardOfMenlo

Điều đó có vẻ như một cảm giác sai lệch về thẩm mỹ; ) Tôi luôn cảm thấy thú vị khi thấy Python bị đánh golf kể từ khi cuốn sách Python đầu tiên tôi đọc nói về cách Python thi hành khả năng đọc.
sadakatsu

Tôi thực sự có một cảm giác sai lệch về thẩm mỹ :)
WizardOfMenlo

Tôi bối rối bởi điểm số của người khác. Tôi đã lấy 10% số điểm của từng chức năng được yêu cầu không sử dụng vòng lặp (tất cả đều là số đó), nhưng những người khác đã lấy 10% toàn bộ số điểm cho mỗi chức năng không sử dụng vòng lặp (có thể là giảm tới 60%). Đó là cách tiếp cận đúng?
sadakatsu

Bạn là cách chính xác để đi, tôi đã có một kỳ vọng không thực tế và vì vậy ban đầu tôi đã nghĩ đến cách tiếp cận 60%, nhưng bây giờ tôi nghĩ rằng 10% sẽ kích thích hơn và sáng sủa hơn giữa hai
WizardOfMenlo

2

Ceylon, 370 * 0,9 = 333 364 * 0,9 = 327,4

Hầu hết các chức năng đó đã có sẵn trong gói ngôn ngữ của Ceylon (mặc dù đôi khi có chữ ký hơi khác nhau), nhưng chúng tôi đang xác định chúng ở đây như được yêu cầu trong câu hỏi.

alias I=>Integer;R[]m<A,R>(R(A)g,A[]l)=>f((R[]x,A y)=>x.append([g(y)]),[],l);A n<A>(A(A)g,A a,I t)=>f((A x,I y)=>g(x),a,r(t));R y<A,R>(Callable<R,A>g,A v)given A satisfies Anything[]=>g(*v);I[]r(I i)=>t((j)=>j,[1,i]);A f<A,O>(A(A,O)g,A a,O[]o)=>if(nonempty o)then f(g,g(a,o[0]),o.rest)else a;R[]t<R>(R(I)g,[I,I]i)=>i[1]<i[0]then[]else[g(i[0]),*t(g,[i[0]+1,i[1]])];

Trên thực tế chỉ có hai trong số các chức năng (tf) thực sự sử dụng đệ quy (tương ứng trên danh sách và số nguyên), các hàm khác dựa trên những hàm này. (Áp dụng là một chút ngoại lệ, nó không thực sự liên quan đến những người khác.)

Tôi diễn giải "Danh sách" là loại tuần tự của Ceylon, đây là một chuỗi các yếu tố được sắp xếp bất biến (có thể trống). [R*]là viết tắt của Sequential<R>- vì một số lý do chúng ta cũng có thể viết nó R[], ngắn hơn một byte.

Một loại hàm là Callable<R, A>, trong đó Alà một loại tuple cho các đối số, như [X, Y, Z](tức là một số kiểu con củaAnything[] ). Như một lối tắt chúng ta có thể viết R(X,Y,Z)thay vì Callable<R,[X,Y,Z]>.

Tôi bí danh IntegerIđể lưu một số byte.

Đây là một phiên bản được định dạng (và hơi bình luận):

// implement functional paradigms
//
// Question: http://codegolf.stackexchange.com/q/58588/2338
// My Answer: http://codegolf.stackexchange.com/a/64515/2338

alias I => Integer;

// map – based on fold.
R[] m<A, R>(R(A) g, A[] l) =>
        f((R[]x,A y) => x.append([g(y)]), [], l);

// nest – based on fold + range, throwing away the second
//        argument in a proxy function.
A n<A>(A(A) g, A a, I t) =>
        f((A x, I y) => g(x), a, r(t));

// apply – this looks quite heavy due to type safety.
//         This uses the "spread operator" *.
R y<A, R>(Callable<R,A> g, A v)
        given A satisfies Anything[] =>
        g(*v);

// range – based on table (using the identity function)
I[] r(I i) =>
        t((j) => j, [1, i]);

// fold – a plain list recursion.
A f<A, O>(A(A, O) g, A a, O[] o) =>
        if (nonempty o) then f(g, g(a, o[0]), o.rest) else a;

// table – an integer recursion.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        i[1] < i[0] then [] else [g(i[0]), *t(g, [i[0] + 1, i[1]])];

Sử dụng "vòng lặp"

Bảng và Bản đồ có thể được thực hiện ngắn hơn bằng cách sử dụng các vòng lặp (thực ra là hiểu trình tự):

// map – using a sequence comprehension:
R[] m<A, R>(R(A) g, A[] l) =>
        [for(a in l) g(a)];

// table – map with an integer range.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        m(g, i[0]..i[1]);

Mặc dù tôi không chắc việc sử dụng ..toán tử cho phạm vi số nguyên có được tính là sử dụng hàm tích hợp hay không. Nếu điều này được cho phép, mã kết quả là đây, độ dài 312:

alias I=>Integer;R[]m<A,R>(R(A)g,A[]l)=>[for(a in l)g(a)];A n<A>(A(A)g,A a,I t)=>f((A x,I y)=>g(x),a,r(t));R y<A,R>(Callable<R,A>g,A v)given A satisfies Anything[]=>g(*v);I[]r(I i)=>t((j)=>j,[1,i]);A f<A,O>(A(A,O)g,A a,O[]o)=>if(nonempty o)then f(g,g(a,o[0]),o.rest)else a;R[]t<R>(R(I)g,[I,I]i)=>m(g,i[0]..i[1]);

(Nó có thể được thực hiện thậm chí ngắn hơn bằng cách xác định r(I i) => 1..i , dẫn đến điểm 301. Mặc dù điều đó thậm chí trông giống như gian lận hơn.)

Nếu ..không được phép, chúng tôi sẽ phải thực hiện lại. Chúng tôi có thể sử dụng những triển khai này cho rt(với những điều mtrên):

// range – based two-limit range 
I[] r(I i) =>
        q(1, i);

// two-limit range implemented recursively
I[] q(I i, I j) =>
        j < i then [] else [i, *q(i + 1, j)];


// table – map with an integer range.
//        (Not sure why the min/max parameters need
//         to be passed in one argument.)
R[] t<R>(R(I) g, [I, I] i) =>
        m(g, q(i[0], i[1]));

Điều này dẫn đến kết quả là 349 byte, tốt hơn phiên bản đệ quy hoàn toàn, nhưng không phải sau khi áp dụng phần thưởng.


0

Groovy (146 byte) (146 * 90% = 131,4)

Tái bút Tôi không biết những gì bạn đang xem là "vòng lặp" trong ngữ cảnh này, tôi chỉ áp dụng phần thưởng sau khi tôi được OP thông báo trong các nhận xét và sẽ xóa nếu 2-3 người dùng khác nói các chức năng thu thập và lặp này là những vòng lặp và tôi không xứng đáng nhận được tiền thưởng. Ngoài ra, nếu bạn muốn gọi tôi bằng cách sử dụng 1..it, vui lòng làm như vậy và tôi sẽ làm lại / cập nhật bytecount của tôi.

m={f,l->l.collect{f(it)}}            // Map
n={f,x,n->n.times{x=f(x)};x}         // Nest
a={f,l->f(l)}                        // Apply
r={1..it}                            // Range (Is this cheating?)
f={f,x,l->l.each{x=f(x,it)};x}       // Fold
t={f,l->(l[0]..l[1]).collect{f(it)}} // Table

Ví dụ đầu vào / đầu ra

f1={2*it}
f2={a,b,c,d,e->a*b*c*d*e}
f3={a,b->a*b}
l=[1,2,3,4,5]
l2=[1,9]
y=5
x=1
println m(f1,l)
println n(f1,x,y)
println a(f2,l)
println r(y)
println f(f3,x,l)
println t(f1,l2)

Đầu ra

MAP:   [2, 4, 6, 8, 10]
NEST:  32
APPLY: 120
RANGE: [1, 2, 3, 4, 5]
FOLD:  120
TABLE: [2, 4, 6, 8, 10, 12, 14, 16, 18]

Hãy tự mình thử: https://groovyconsole.appspot.com/edit/5203951758606336


Về mặt kỹ thuật này không sử dụng các vòng lặp, vì vậy hãy nhớ phần thưởng! Khác, câu trả lời tuyệt vời!
WizardOfMenlo

Về mặt kỹ thuật không có vòng lặp?! Có thật không?! .each {} .times {} .collect {} là các trình vòng lặp.
Bạch tuộc ma thuật Urn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.