클린 골프에서의 팁


17

Clean에서 골프를 치기 위해 어떤 일반적인 팁이 있습니까? 일반적으로 코드 골프 문제에 적용 할 수 있고 최소한 Clean에 특정한 아이디어 만 게시하십시오.

Clean에 대해 들어 본 적이 없다면 여기 에서 더 자세히 알아볼 수 있습니다 .
또는 대화방에 참여할 수 있습니다 .

답변:


10

import StdEnv가능하면 피하십시오

액세스에 내장 된 기능도 겉으로는 기본 것과 같은 (==)map, import 문은 일반적으로 필요하다 import StdEnv는 가장 일반적인 모듈처럼 수입하기 때문에 StdInt, StdBool등 (참조 여기에 더 많은 정보에 대한 StdEnv).

그러나 일부 문제의 경우 이러한 가져 오기를 피하고 목록 이해 및 패턴 일치와 같은 핵심 언어 기능을 사용할 수 있습니다.

예를 들어

import StdEnv 
map f list

하나는 쓸 수있다

[f x\\x<-list]

대안 목록 :

필요한 일부 함수 또는 함수 호출 import StdEnv, 가져 오기가 필요없는 대안 및 대략적인 바이트 추정값 저장.

  • hd-> (\[h:_]=h), ~ 6 바이트
  • tl-> (\[_:t]=t), ~ 6 바이트
  • map f list-> [f x\\x<-list], ~ 10 바이트
  • filter p list-> [x\\x<-list|p x], ~ 11 바이트
  • (&&)-> %a b|a=b=a;%, ~ 6 바이트
  • (||)-> %a b|a=a=b;%, ~ 6 바이트
  • not-> %a|a=False=True;%, ~ 1 바이트
  • and-> %[a:r]|a= %r=a;%_=True, ~ 0 바이트
  • or-> %[a:r]|a=a= %r;%_=False, ~ 0 바이트

직접 대체는 가져 오기보다 더 많은 바이트를 생성하기 때문에 마지막 몇 개는 실제로 바이트를 절약 할 수 없지만 목록에 대한 재귀가 필요한 경우 가능할 수 있습니다.

이 팁은 여기에서 성공적으로 사용 되었습니다 .


아닌가 import StdEnv+ a and b이상 (21 바이트) 작은 %[a:r]|a= %r=a;%_=True하지만, (22 바이트)? 아니면 import StdEnv+ a=True and b=True(31 바이트)입니까?이 경우 실제로 더 짧습니까? (저는 Clean, btw에서 프로그래밍 한 적이 없습니다.)
Kevin Cruijssen

@KevinCruijssen 방금 채팅에서 그 내용을 논의하고 있었습니다 . 어쨌든 프로그램이 목록을 통해 되풀이 해야하는 경우를 제외하고는 바이트를 절약 할 가능성이 거의 없습니다.
Laikoni

4
그래. 대안으로 저장되는 바이트 수 map f list -> [f x\\x<-list] (11 bytes saved)(또는 유사한 것)를 나타내는 것이 유용 할 수도 있습니다 .
Kevin Cruijssen

@KevinCruijssen 님.
Laikoni

5

언어를 배우는 방법을 알고

결국, 사람들은 어떻게 사용할 수없는 언어로 골프를 칠 수 있습니까!

온라인

Clean은 잘 알려 지거나 문서화 된 언어가 아니며, 그 이름으로 인해 이러한 문제를 해결하는 데 필요한 리소스를 쉽게 찾을 수 없습니다.

Clean은 원래 Concurrent Clean 이라고 하며 Clean과 관련된 거의 모든 문서의 서문에서 여전히 사용됩니다. 따라서 Clean을 찾는 경우에는 Concurrent Clean을 찾으십시오.

Clean과 Haskell의 더 큰 유사점 중 하나는 Clean 과 함께 제공되는 라이브러리를 다루는 함수 검색 엔진 인 Cloogle 의 존재입니다 .

토지 상에서

Clean과 함께 제공되는 라이브러리는 적절하게 주석 처리되고 다소 자체 문서화 된 Clean 소스 파일 형식이며 IDE를 사용하여 찾아 볼 수 있습니다.
(또한 전체 예제 프로그램과 함께 제공됩니다 $INSTALL/Examples.)

말하자면, Windows 버전의 Clean에는 IDE가 포함되어 있습니다. 현대 표준에 의해 상당히 제한적이지만 텍스트 편집기와 명령 줄을 사용하는 것보다 세상이 더 좋습니다.
학습의 맥락에서 가장 유용한 두 가지 기능은 다음과 같습니다.

  • 오류를 두 번 클릭하여 어느 줄에 있는지 확인할 수 있습니다
  • 모듈 이름을 강조 표시하고을 눌러 [Ctrl]+[D]정의 파일을 열거 나 (또는 [Ctrl]+[I]구현 파일에 사용) 다음 을 사용하여 정의 파일 과 구현 파일 간을 전환 할 수 있습니다.[Ctrl]+[/]

4

문자 인코딩 잊어 버려

Clean의 컴파일러는 소스 파일을 저장 한 인코딩, 파일의 바이트 값에 대해서는 신경 쓰지 않습니다. 이것은 몇 가지 깔끔한 결과를 가져옵니다.

소스 코드 본문에는에 대한 것 외에도 인쇄 가능한 ASCII 문자에 해당하는 코드 포인트가있는 바이트 만 허용됩니다 \t\r\n.

리터럴 :

에서는 String하고 [Char]리터럴 ( "stuff"['stuff']각각), 0 바이트를 제외한 그 경고와 함께 사용할 수 있습니다 "'(대한 이스케이프해야 String하고 [Char]각각), 그리고 줄 바꿈과 carraige 반환 해야한다 로 대체 \n하고 \r(도 각각).

에서 Char리터럴, 0을 제외한 모든 바이트는 그 의미 허용된다 :

'\n'

'
'

동일하지만 두 번째는 1 바이트 더 짧습니다.

탈출 :

표준 문자 이스케이프 \t\r\n(등) 등을 제외하고 Clean의 모든 비 숫자 이스케이프 시퀀스는 슬래시이거나 이스케이프가 포함 된 리터럴을 구분하는 데 사용되는 인용 부호입니다.

숫자 이스케이프 시퀀스의 경우 숫자는 3 자리 숫자 다음에 끝나는 8 진수 값으로 처리됩니다. 이 수단은 문자 뒤에 널 원한다면 것을 1A의를 String, 사용해야하는 "\0001"(또는 "\0\61") 및 없습니다 "\01" . 당신은 아무것도 탈출을 따를 경우, 하지만, 숫자, 당신은 앞에 0을 생략 할 수 있습니다.

결과 :

Clean이 소스 파일을 처리하는 방법에 대한이 문제는 인덱스 저장 (물론 최대 255 개)과 같이 코드-골프에 여러 용도로 사용되는 기본 -256 단일 숫자 숫자의 시퀀스를 허용 String하고 ['Char']효과적으로 만들 수 있습니다 .


3

기호가있는 이름 함수

함수를 정의 할 때 !@$%^&*~-+=<:|>.?/\식별자 사이에 공백을 생략 할 수 있으므로 영숫자 문자를 사용 하는 것보다 일부 조합을 사용하는 것이 더 짧은 경우가 많습니다 .

예를 들어 : ?a=a^2가보다 짧고 f a=a^2호출하는 것도 짧습니다.

그러나 :

함수 식별자가 다른 심볼에 인접하여 사용되는 경우 다른 심볼 이지만 유효한 식별자를 결합하여 결합 할 수있는 경우 모두 하나의 식별자로 구문 분석되며 오류가 표시됩니다.

예를 들면 다음 ?a+?b과 같습니다.? a +? b

또한 :

Clean에서 가져온 식별자를 덮어 쓸 수 있으므로 아직 사용되지 않은 유일한 단일 문자 기호 식별자 StdEnv@$?입니다. ^-+더 많은 기호 식별자가 필요한 경우 덮어 쓰기 등이 유용 할 수 있지만 사용중인 식별자를 덮어 쓰지 않도록주의하십시오.


3

K 노드를 알고

기능적 언어에서 가장 강력한 구조 (골프 용)는 다음과 같습니다 let ... in ....
물론 깨끗하고, 더 좋은 점이 #있습니다.

노드 란 무엇입니까?

Clean #과 유비쿼터스 |(pattern guard)는 모두 '노드 표현'으로 알려져 있습니다.
특히, 그들은 당신이 imperatively- 프로그램 할 수 흉내 청소에 (여기 정말 좋다!).

#(렛 전) :

둘 다 문자열로 주어진 정수 값과 그 문자의 합을 곱한 값을 계산합니다.

f s=let i=toInt s;n=sum[toInt c\\c<-:s]in n*i

f s#i=toInt s
#s=sum[toInt c\\c<-:s]
=s*i

버전이 얼마나 #짧은 지, 어떻게 재정의 할 수 있는지 확인하십시오 s. 변수를받을 때 가지고있는 값이 필요하지 않은 경우에 유용하므로 이름을 재사용 할 수 있습니다. ( let그렇게하면 문제가 생길 수 있습니다)

그러나 let다음과 같은 것이 필요할 때 사용 이 더 쉽습니다.flip f = let g x y = f y x in g

|(패턴 가드) :

Clean의 패턴 가드는 다른 많은 기능 언어의 언어와 마찬가지로 사용할 수 있지만 명령형처럼 사용할 수도 있습니다 if ... else .... 그리고 삼항식의 짧은 버전.

예를 들어, 모두 정수의 부호를 반환합니다.

s n|n<>0|n>0=1= -1
=0

s n=if(n<>0)if(n>0)1(-1)0

s n|n>0=1|n<0= -1=0

물론 가드를보다 전통적으로 사용하는 마지막 것이 가장 짧지 만 첫 번째는 중첩 할 수 있음을 보여줍니다 (그러나 레이아웃 규칙에서 두 줄의 무조건 반환 절 만 동일한 줄에 나타날 수 있음). 첫 번째는 논리적으로 수행합니다.

노트:

이 표현식은 기본적으로 어디서나 사용할 수 있습니다. 람다에서, case ... of, let ... in, 등


1

당신이 사용하는 경우 String사용해야합니다Text

문자열로의 변환 및 문자열의 조작 ( 종류가 아닌 {#Char}/ 종류)은 상당히 길고 골프에 좋지 않습니다. 그만큼String[Char]Text모듈 요법이.

변환:

Text정의 된 <+두 가지 유형 의 연산자 를 toString정의합니다.
이 연산자 는 최소한 19 바이트를 절약 a<+b하는 것과 같습니다 . 추가 가져 오기를 포함 시켜서 한 번만 사용 하더라도 여전히 14 바이트를 절약합니다!toString a+++toString b,Text

시장 조작:

Text에서 누락 된 몇 가지 문자열 조작 스테이플을 정의합니다 StdEnv.

  • +문자열 의 연산자 +++( 보다StdEnv )
  • indexOf-1대신 C와 같은 동작이 반환 됩니다.Nothing 실패
  • concat문자열 목록을 연결합니다.
  • join구분자 문자열을 사용하여 문자열 목록을 조인합니다.
  • split문자열을 하위 문자열의 문자열 목록으로 분할합니다.

1

짧은 람다 사용

때로는 람다 식을 사용하여 자신을 찾으십시오 ( map또는 sortBy, 등 으로 전달 ). 이 작업을 수행 할 때 (람다 작성) 할 수있는 방법이 많이 있습니다.

옳은 길:

이것은 sortBy가장 긴 것에서 가장 짧은 것까지 관용적 람다 정렬 목록이 있습니다.

sortBy (\a b = length a > length b)

다른 올바른 방법 :

를 사용하는 경우 Data.Func에도 할 수 있습니다

sortBy (on (>) length)

짧은 방법 :

이것은 동일하지만 골퍼 구문

sortBy(\a b=length a>length b)

다른 방법:

컴포지션 사용은 이번에는 짧지 않지만 때로는 짧을 수 있습니다.

sortBy(\a=(>)(length a)o length)

다른 방법 :

여기에 약간 고안되어 있지만 람다에서 경비원을 사용할 수 있습니다

sortBy(\a b|length a>length b=True=False)

또한 노드 이전 식

sortBy(\a b#l=length
=l a>l b)

노트:

람다에는 두 가지 형태가 더 (\a b . ...)있으며 (\a b -> ...), 후자는 =변형 과 동일 하며 , 후자는 변형 과 동일 하며 종종 람다를 정의하는 대신 무언가의 속성에 액세스하려고하는 것처럼 보입니다. 사용하지 마십시오.


1
당신의 golfed 프로그램의 일부를 본 후, 나는 인상을 가지고 있었다 \a=... 이었다 청소의 일반적인 람다 구문 : P
Ørjan 요한센

여기에 사용 된대로 람다에 가드를 추가 할 수도 있습니다 . 이것은 문서화되어 있지 않지만 (언어 보고서와 모순됩니다) 작동합니다. 또한, ->=람다 위해 멀리 컴파일러에 관한 한 동일 ( ->이전 구문이다). 오직 .다릅니다 (그러나 나는 정확히 어떻게 모르겠습니다).

그리고이 특정 예에서는을 사용하는 것을 고려할 수 on(<)length있지만 Data.Func가져 오기는 이미 필요하지 않은 경우 가져옵니다.

@ 킬란 쿨. 오늘 나중에 업데이트하겠습니다. #람다에서 let-before ( )를 사용할 수도 있다고 생각합니다 .
많은

그래 넌 할수있어 :-)

0

문자 목록 리터럴 사용

문자 목록 문자는 같은 것을 작성하는 약식 방법 ['h','e','l','l','o']으로 ['hello'].

이것은 표기법의 한계가 아닙니다. 예를 들면 다음과 같습니다.

  • repeat'c'하게 ['c','c'..]된다['cc'..]
  • ['z','y'..'a'] 된다 ['zy'..'a']
  • ['beginning']++[a,b,c]++['end'] 된다 ['beginning',a,b,c,'end']
  • ['prefix']++suffix 된다 ['prefix':suffix]

이것도 일치합니다.

  • ['I don't care about the next character',_,'but I do care about these ones!']

0

때때로 code더 짧습니다

Clean은 표준 라이브러리에 유용한 함수가 많이 있습니다. *World 와 사용*World 코드 골프에서 하는 것은 일반적으로 나쁜 생각입니다.

이 문제를 해결하기 위해 종종 ccall 내부 code블록을 대신 사용할 수 있습니다 .

몇 가지 예 :

시스템 시간

import System.Time,System._Unsafe
t=toInt(accUnsafe(time))

위는 58 바이트이지만 다음을 사용하여 17 바이트 (40 + 1까지)를 절약 할 수 있습니다.

t::!Int->Int
t _=code{ccall time "I:I"
}

난수

이것은 자체적으로 바이트를 저장하지는 않지만 목록을 전달하지 않아도됩니다. genRandInt

s::!Int->Int
s _=code{ccall time "I:I"ccall srand "I:I"
}
r::!Int->Int
r _=code{ccall rand "I:I"
}

다른 용도

코드 골프 에서이 용도로 주로 사용되는이 두 가지 외에도 모든 syscall을 포함하여 모든 명명 된 함수를 호출하고을 사용하여 임의의 어셈블리를 instruction <byte>포함하며 ABC 시스템의 코드를 포함 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.