Diyet Haskell yapalım


21

Haskell’in şöyle yazılabilen tülleri var.

(a,b,c)

Ancak bu sadece sözdizimsel şeker

(,,)a b c

Genel olarak, bir N tuple ile oluşturulabilir , n-1 , arasında s (... )unsurları, ardından boşluk ile birbirlerinden ayrılmıştır. Örnek 7-tuple için (1,2,3,4,5,6,7)oluşturulabilir

(,,,,,,)1 2 3 4 5 6 7

Haskell'in 1 teli olmadığı için oluşturulamaz. Ayrıca boş tüllerden sorumlu tutulmayacaksınız.

İç içe tuples, işlemlerin sırasını geçersiz kılmak için parens kullanılarak oluşturulabilir.

((1,2),3) == (,)((,)1 2)3

Tüm sözdizimsel şekeri Haskell'den çıkarma arayışımızın bir parçası olarak sizden, sözdizimsel şekeri Haskell'in konuşmalarından da kaldıran bir program yazmanızı isteyeceğim.

Programınız bir dize, bir dizi veya şekerli bir dize temsil eden bir dize almalı ve "şekersiz" bir dize temsil eden bir dize vermelidir. Giriş tuples'lerinde sadece pozitif tamsayılar veya diğer tuples'ler bulunacaktır.

Burada golf oynadığımız için çıktılarınız kısa olmalı. Gereksiz içermemelidir

  • Spaces. Boşluklar yalnızca bir tuple işlevinin argümanlarını ayırmak için kullanılmalı ve bir )veya daha önce görünmemelidir.(

  • Parantez. Parantezler, yalnızca tuple işlevleri oluşturulurken veya yuvaları yerleştirirken kullanılmalıdır.

Bu bir sorusudur, bu yüzden cevaplar daha az byte'ın daha iyi olmasıyla byte olarak puanlanacaktır.

Test durumları

(1,2)     -> (,)1 2
(1,2,3)   -> (,,)1 2 3
((1,2),3) -> (,)((,)1 2)3
(1,2,3,4) -> (,,,)1 2 3 4
(1,(2,3)) -> (,)1((,)2 3)
(10,1)    -> (,)10 1

Eğer bir şey kaçırmıyorsam, 1 trolü örtüyorsun ama boş tlbeyi kapatmıyorsun ..? Boş tüpler geçerli giriş mi?
tamamen insan

3
@totallyhuman Boş tuples ile uğraşmanıza gerek yok.
Buğday Sihirbazı,

5. testin ekstra süresi var,
H.PWiz

2
Ayrıca "sayılar" ile "pozitif tamsayılar" mı kastediyorsunuz?
Outgolfer Erik

2
Önerilen test durumları: ((1,(2,3)),4,(5,6))ve (1,(2,3),4).
Ørjan Johansen

Yanıtlar:


17

Haskell , 169 148 bayt

init.tail.fst.([]%)
p:k="(,"
l%('(':r)|(y,x:s)<-[]%r,m<-y:l=last$m%(p:s):[(p:p:(l>>k)++x:foldl(\r x->x++[' '|x>k,r>k]++r)[x]m,s)|x<',']
l%r=lex r!!0

Çevrimiçi deneyin! Düğmeyi bir dize olarak alır. init.tail.fst.([]%)isimsiz ana işlevdir. Örneğin onu bağlayın fve f "(3,(14,1),4,7)"verimi olan benzerini kullanın "(,,,)3((,)14 1)4 7".

Giriş neden bir Haskell bağlantısı olarak sağlanmadı? Haskell güçlü bir şekilde yazıldığından, bir tuple (1,2)tip (Int,Int)1'e ve bir tuple (1,(2,3))tipe sahiptir (Int,(Int,Int)). Bu nedenle, birinci tür bağlantı parçasını kabul eden bir işlev, ikinci türe uygulanamaz ve özellikle isteğe bağlı bir bağlantı parçası 2 alan bir işlev olamaz .

Açıklama:

  • p:k="(,"atamak için kısa yoldur petmek '('ve kkarşı ",".
  • (%)özyinelemeli ayrıştırma ve dönüştürme işlevidir. İlk argüman zaten ayrıştırılmış tuple girişlerinin bir listesidir, ikinci argüman orijinal dizginin kalanıdır. Her çağrı, geçerli dönüştürülmüş demetin bir dizgisini (bir dizge olarak ve parantez içine alınmış) ve dizenin geri kalanını döndürür.
    • l%('(':r)Dize bir açılış braketi ile başlıyorsa, yeni bir tuple girişi ayrıştırmamız gerekir.
      (y,x:s)<-[]%rTekrarlı olarak %bir tuple girişi uygular ve ykalan dizgeyi sonraki karaktere xve dizginin geri kalanına ayırırız s.
      m<-y:lYeni girişi y, mevcut bulunan girişlerin mevcut listesine ekliyoruz lve sonucu çağırıyoruz m.
    • Bir sonraki karakter xşimdi bir virgül ,veya kapanış parantezidir ). Bu last$ <B> :[ <A> |x<',']sadece daha kısa bir yazı biçimidir if x == ')' then <A> else <B>.
    • Eğer bir ,sonraki ise, bir sonraki girişi m%(p:s)tekrarlı bir şekilde ayrıştırmamız gerekir: Doğru davaya son vermek ve daha önce bulunan girişlerin listesini iletmek için bir açılış dirseği hazırlarız m.
    • Aksi takdirde x == ')', şu anki dizgiyi bitirdik ve gerekli dönüşümü yapmamız gerekiyor:(p:p:(l>>k)++x:foldl(\r x->x++[' '|x>k,r>k]++r)[x]m,s)
      • p:p:(l>>k)++x:Eğer n girdi bulduysak , o mzaman n elementi vardır ve yen son bulunan elemanı eklemeden önce n-1 girişi vardır. Bir eleman dizisi için n-1'e ihtiyaç duyduğumuzdan ve “listeyi elemanların olduğu kadar kendisiyle birleştirmek” gibi listelerde çalıştığımız ,için bu kullanışlı bir nözelliktir . Böylece, bu ilk kısım, benzeri bir dizi verir .l>>kky"((,,,)"
      • foldl(\r x->x++[' '|x>k,r>k]++r)[x]melemanlarını birleştirir m(nedeniyle ön yenisini ekleyerek de ters olarak, mher ikisi de sayı ise, yalnızca iki eleman arasında boşluk eklenirken kendisi ters inşa edilmiştir): [' '|x>k,r>k]şu andaki girişleri kontrol xve rsözlük sırasında karşılaştırarak numaraları vardır Onlara ","- eğer sayı değilse, zaten parantez içine alınmış bir tuple gösterimidir ve '(' < ','tutar.
    • Desen maç ise l%('(':r)hemen başında başarısız, o zaman son satırında sonuna kadar: l%r=lex r!!0. Bu, bir sayıyı ayrıştırmamız ve sayı ile dizinin kalanını döndürmemiz gerektiği anlamına gelir. Neyse ki lextam olarak bunu yapan bir işlev var (Sadece sayıları değil, bir sonraki geçerli Haskell belirtecini ayrıştırır). Ancak sonuçta ortaya çıkan demet bir listeye sarılır, bu nedenle listenin !!0ilk öğesini almak için kullanırız .
  • init.tail.fst.([]%)Bir dize alan ve %boş bir listeyle uygulanan ana işlevdir . Bir girdi için "(1,2)", ([]%)verimler uygulandığında ("((,)1 2)",""), dış bağlantı ve braketlerin çıkarılması gerekir. fstdemetin ilk elemanını alır, tailkapanış dirseğini ve initaçıklığı çıkarır .

Düzenleme: Toplam 21 byte golf oynadığı için @ Ørjan Johansen'e teşekkürler !


1 Aslında, tür (Num t1, Num t) => (t, t1) , ancak bu farklı bir hikaye.

2 Girdileriyle gerçekten çalışamayan id gibi polimorfik fonksiyonların yoksayılması .


1
Biri typeclass kullanarak polimorfik işlevi yazabilirsiniz Desugarable, ama bir için beyan örneklerine olurdu Intve tüm tanımlama grubu tipleri.
Bergi

1
gkısaltılabilir foldr1(\x r->x++[' '|x>k,r>k]++r)ve satır içi kısaltılabilir .
Ørjan Johansen

@Bergi:… ve biri gerçekten tüm tuple tipleri için örnek ilan edemez . :-) (Deneyin: show (1,2,3,4,5,6,7,8,9,0,1,2,3,4,5)GHCi’de, ardından bir tane ekleyin ,6ve tekrar deneyin.)
wchargin

1
Altı bayt için satır çizgisini geliştirme: Kullanın m<-y:l, sağ yerine sola katlayın ve [x]başlangıç ​​değeri olarak kullanın . Çevrimiçi deneyin!
Ørjan Johansen

1
fisimsiz olabilir init.tail.fst.([]%).
Ørjan Johansen

11

Haskell, 141 bayt138 bayt (Ørjan Johansen sayesinde)

import Language.Haskell.TH
f(TupE l)='(':tail(","<*l)++')':""%l
q%(LitE(IntegerL i):l)=q++show i++" "%l
_%(e:l)='(':f e++')':""%l
_%[]=[]

ftürü var Exp -> String.

  • Girdi: Bir Şablon HaskellExp devri (yani, keyfi tip Haskell değerlerinin standart AST temsili - temel olarak tip kontrolünden önce Haskell kodunu ayrıştırır); sadece negatif olmayan tamsayı sayıları ve bu tür diğer başlıkları içeren bir yazıyı temsil etmelidir.

  • Çıktı: Bu tuple ifadesi için desugared sözdizimini içeren bir dize.

Demo:

$ ghci TupDesugar.hs 
GHCi, version 8.3.20170711: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Loaded GHCi configuration from /home/sagemuej/.ghci
[1 of 1] Compiling Main             ( TupDesugar.hs, interpreted )
Ok, 1 module loaded.
*Main> :set -XTemplateHaskell -XQuasiQuotes
*Main> f <$> runQ [|(1,2)|]
"(,)1 2"
*Main> f <$> runQ [|(1,2,3)|]
"(,,)1 2 3"
*Main> f <$> runQ [|((1,2),3)|]
"(,)((,)1 2)3"
*Main> f <$> runQ [|(1,2,3,4)|]
"(,,,)1 2 3 4"
*Main> f <$> runQ [|(1,(2,3))|]
"(,)1((,)2 3)"
*Main> f <$> runQ [|(10,1)|]
"(,)10 1"

2
Değişebilirsin ")"++için ')':iki yerde ve sonrasında yerden tasarruf tailbunu dışarıdan parantez hareket ettirerek.
Ørjan Johansen

7

Haskell , 119 bayt

data T=I Int|U[T]
f(U t)="(("++init(t>>",")++')':foldr(\x y->f x++[' '|f x>",",y>","]++y)")"t
f(I n)=show n
init.tail.f

Çevrimiçi deneyin! Bu, Ttupleri temsil etmek için özel bir veri türü kullanır , yani bir tuple ((1,2),3)olarak temsil edilir U[U[I 1,I 2],I 3]. Örnek kullanım: init.tail.f $ U[U[I 1,I 2],I 3]verim (,)((,)1 2)3.



4

GNU sed, 149 82 + 2 = 84 bayt

-rBayrak için +2 bayt .

y/(),/<>'/
:
s/([^<>']+)'/,\1 /
t
s/ ?<(,+)([^>]+)>/((\1)\2)/
t
s/^.|(\)) |.$/\1/g

Çevrimiçi deneyin!

açıklama

y/(),/<>'/                   # Replace parens and commas with brackets and apostrophes
:
  s/([^<>']+)'/,\1 /.          # Remove each apostrophe and insert comma after <
  t                            # Branch to : if substitution was made
  s/ ?<(,+)([^>]+)>/((\1)\2)/  # Change <,,,...> to ((,,,)...)
  t                            # Branch to : if substitution was made
s/^.|(\)) |.$/\1/g           # Remove outermost ()s and extra spaces

Bu, daha karmaşık bazı durumlarda başarısız olur: ((1,(2,3)),4,(5,6))ve (1,(2,3),4).
Ørjan Johansen

@ ØrjanJohansen İyi yakala. Kahvaltıdan sonra bir göz atacağım.
Ürdün

3

JavaScript, 75 bayt

f=a=>`(${t=a.map(x=>'')})${a.map(v=>t=1/v?1/t?' '+v:v:`(${f(v)})`).join``}`

Sayı dizisi | dizi, çıktı dizisi.

Neil sayesinde, 2 bayt tasarruf edin


(1/t?' ':0)+volabilir 1/t?' '+v:v.
Neil

2

Mathematica, 94 bayt

{"(",","&/@Most@#,")",c=1>0;(xIf[j=ListQ@x,c=j;"("<>#0@x<>")",If[c,c=j;x," "<>x]])/@#}<>""&

Yazdırılamaz U+F4A1, yerleşik bir Functionişlev içerir.

Bir tane al List tamsayı arasında Stringlar. Bu izin verilmez, bu 10 daha ekleyerek byte düzeltilebilir (bu sürüm bir sürer Listait Lists / Integers):

{"(",","&/@Most@#,")",c=1>0;(xIf[j=ListQ@x,c=j;"("<>#0@x<>")",If[c,c=j;""," "]<>ToString@x])/@#}<>""&

2

Pip , 45 bayt

{Y"()"b:yJ',X#a-1Fcab.:c>0?s.cyJ(fc)bR") "')}

Bu, listeyi argüman olarak alan bir fonksiyondur. Çevrimiçi deneyin!

Yorumlanan sürüm

; Define an anonymous function (the argument is available inside as the variable a)
{
  ; Yank the string "()" into y variable
  Y "()"
  ; Create a string of len(a)-1 commas, join y on it, and assign to b
  b: y J ',X#a-1
  ; For each item c in a
  F c a
    ; Concatenate to b the following expression
    b .:
      ; Is c integer or list?
      ; (If c is a positive integer, c>0 is true; but if c is a list, c>0 is false)
      c>0 ?
        ; If c is integer, concatenate space followed by c
        s.c
        ; If c is list, call function recursively on c and use the result to join y
        yJ(fc)
  ; Replace ") " with ")" in b and return the resulting string
  b R ") " ')
}

2

JavaScript (ES6), 88 84 bayt

f=a=>a.reduce((s,e)=>s+=e[0]?`(${f(e)})`:/\)$/.test(s)?e:' '+e,`(${[...a].fill``})`)

Bir dizi tamsayı ve dizi alır. Düzenleme: s+=İki ayrı kullanım yerine 1 bayt kullanılarak kaydedildi s+. İçteki üçlüyü basitleştirebildiğim için 3 bayt daha kaydetti. @ Tsh'in fikirlerini çalarsam, onu 76 bayta indirebilirim:

f=a=>a.reduce((s,e)=>s+=t=1/e?1/t?' '+e:e:`(${f(e)})`,`(${t=a.map(_=>``)})`)

Your program should take either a tuple or a string representing a sugary tupleBir dizi dizinin / tamsayının iyi olması gerektiğini varsayardım.
JungHwan Min 04:17

1
Buna izin verildiğinden emin olun
Buğday Sihirbazı,

1

R, 316 bayt?

(Bayt'ı saymanın doğru yolundan emin olmamalısınız ... artı bu harika bir çözüm değil ama zaman harcadığımdan beri göndermek istedim ...)

p=function(x){
x=eval(parse(text=gsub("\\(","list(",x)))
f=function(j,r=T){
p=paste
s=if(r){"("}else{"(("}
o=paste0(s,p(rep(",",length(j)-1),collapse=""),")")
n=lengths(j)
for(i in seq_along(n)){
v=j[[i]]
if(n[i]>1){v=f(v,F)}
o=p(o,v)}
if(!r){o=p(o,")")}
o=gsub(" *([()]) *","\\1",o)
return(o)}
f(x)
}

Test durumları:

> p("(1,2)")
[1] "(,)1 2"
> p("(1,2,3)")
[1] "(,,)1 2 3"
> p("((1,2),3)")
[1] "(,)((,)1 2)3"
> p("(1,2,3,4)")
[1] "(,,,)1 2 3 4"
> p("(1,(2,3))")
[1] "(,)1((,)2 3)"
> p("(10,1)")
[1] "(,)10 1"


2
261 bayta kadar golf oynadı . Ne değiştiğime dair bir açıklama bırakabilirim, ama ironik bir şekilde benim de gitmem gerekiyor ... Ama + 1, kafamı bu şekilde saramadım; iyi iş!
Giuseppe

0

JavaScript (ES6), 72 bayt

f=(a,b="",c="")=>a.map?b+"("+a.map(x=>'')+")"+a.map(x=>f(x,"(",")"))+c:a

Giriş: Sayı ve / veya dizi içeren dizi

Çıktı: string

Kullanım: f ([...])

Tüm test durumlarını tamamlar, iyileştirmeler memnuniyetle karşılanır


0

C, 308 veya 339 bayt

#include <ctype.h>
#define p putchar
f(s,e,c,i,l)char*s,*e,*c;{i=1,l=40;if(*s++==l){p(l);for(c=s;i;i+=*c==l,i-=*c==41,i+*c==45&&p(44),c++);p(41);}for(;s<e;s=c){for(i=0;isdigit(*s);s+=*s==44)for(i&&p(32),i=1;isdigit(*s);s++)p(*s);*s==l&&p(l);for(c=s,i=1;++c,c<=e&&i;i+=*c==l)i-=*c==41;f(s,c-1);*s==l&&p(41);}}
#define g(x) f(x, x+strlen(x))

308 veya 339 bayt, bir işaretçiyi giriş dizesinin sonuna geçirip geçirmemesine bağlı olarak; Son satır, yalnızca bir dize değişmezinin uzunluğunu hesaplamak zorunda kalmadan doğrudan geçirilmesine izin vermek için vardır.

açıklama

Oldukça basit bir algoritma. Geçerli derinlikteki virgüllerin sayısını sayar, bunları bir tuple yapıcısı olarak yazdırır, sonra ard arda kaçan argümanları takip eder (sayılar arasındaki boşluklar, parantez arasında iç içe tuples).

#include <stdio.h>
#include <ctype.h>
typedef enum { false, true } bool;

void tup2ptsfree(char *s, char *e)
{
  int depth;
  char *c;

  if (*s++ == '(') { /* If we are at the start of a tuple, write tuple function `(,,,)` (Otherwise, we are at a closing bracket or a comma) */
    putchar('(');
    /* do the search for comma's */
    c=s; /* probe without moving the original pointer */
    for (depth=1; depth != 0; c++) {
      if (*c == '(') depth++;
      if (*c == ')') depth--;
      if (*c == ',' && depth == 1) putchar(','); /* We have found a comma at the right depth, print it */
    }
    putchar(')');
  }
  while (s < e) { /* The last character is always ')', we can ignore it and save a character. */
    bool wroteNumber;
    for (wroteNumber=false; isdigit(*s); wroteNumber = true) {
      if (wroteNumber) p(' ');           /* If this is not the first number we are writing, add a space */
      while (isdigit(*s)) putchar(*s++); /* Prints the entire number */
      if (*s == ',') s++;                /* We found a ',' instead of a ')', so there might be more numbers following */
    }
    /* Add escaping parenthesis if we are expanding a tuple (Using a small if statement instead of a large branch to prevent doing the same thing twice, since the rest of the code is essentially the same for both cases). */
    if (*s == '(') putchar('(');
    /* Find a matching ')'... */
    c=s+1;
    for (depth=1; c <= e && depth != 0; c++) {
      if (*c == '(') depth++;
      if (*c == ')') depth--;
    }
    /* Found one */
    /* Note how we are looking for a matching paren twice, with slightly different parameters. */
    /* I couldn't find a way to golf this duplication away, though it might be possible. */
    /* Expand the rest of the tuple */
    tup2ptsfree(s, c-1);
    /* idem */
    if (*s == '(') putchar(')');
    /* Make the end of the last expansion the new start pointer. */
    s=c;
  }
}

#define h(x) tup2ptsfree(x, x+strlen(x))

Test durumları ve uygulama

#include <stdio.h>

#define ARRAYSIZE(arr) (sizeof(arr)/sizeof(*arr))
static char *examples[] = {
  "(1,2)",
  "(10,1)",
  "(1,2,3)",
  "(1,2,3,4)",
  "((1,2),3)",
  "(1,(2,3))",
  "(1,(2,3),4)",
  "((1,2),(3,4))",
  "((1,(2,3)),4,(5,6))",
  "((1,((2,3), 4)),5,(6,7))",
  "(42,48)",
  "(1,2,3,4,5,6,7)"
};

int main(void)
{
  int i;
  for (i=0; i < ARRAYSIZE(examples); i++) {
    printf("%-32s | \"", examples[i]);
    g(examples[i]); /* Test with golfed version */
    printf("\"\n");
    printf("%-32s | \"", examples[i]);
    h(examples[i]); /* Test with original version */
    printf("\"\n");
  }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.