SnocList recursive view 형 드라이버를 개발해 보세요 in Idris2
원래 뷰는...
뷰란 데이터 구조자의 분해 이외의 방법에 따라 데이터형을 분해하고 해석하는 것을 말한다. 즉, (View)를 보기 위한 데이터형이다.Irdris에서 View는 의존형 데이터형을 사용하는 것으로 정의되었고 그 유형 구조자는 목표 데이터의 의도를 분해하는 형식을 유지하고 있다.구체적인 예를 살펴보자.
SnocList view
List는 Idris의 Produde에 의해 정의됩니다.
익숙하신 것 같습니다.현재, 예를 들어, 만약에 어리석게reverse 함수를 정의하여 첫 번째 매개 변수의 목록을 패턴적으로 일치시키면, 보통 아래의 데이터 구축자에 따라 분해됩니다.
data List (a : Type) -> Type where
Nil : List a
(::) : (x : a) -> (xs : List a) -> List a
현재 이naive의 실현을 개선하기 위해 위의 매개 변수의 lst를 끝에서 분해하고 싶습니다.그렇게 생각하는 순간일 거예요.하지만 번역할 수 없습니다.매개 변수의 패턴 일치는 데이터 건설기를 따라 진행되기 때문이다.이걸 해결하는 게 뷰야.
reverse : (lst : List a) -> List a
reverse [] = []
reverse (x :: xs) = reverse xs ++ [x]
SnocList는 (xs:Lista)에 글자가 붙었다.2개의 데이터 구조자가 있는데,Enpty는 빈 목록의 SnocList를 표시하고, Snoc는 x:a와 xs:Lista, 그리고 snoc:SnocList xs는 (xs++[x]) 형식으로 목록을 봅니다.지금도
-- これは通らない
reverse : (lst : List a) -> List a
reverse [] = []
reverse (xs ++ [x]) = x :: reverse xs
함수를 통해 임의의 xs:Lista를 SnocList xs로 변환할 수 있다면 SnocList의 데이터 구조자에 따라 패턴을 매칭하여 xs의 끝 요소를 끊임없이 추출할 수 있다.SnocList를 사용한 Reverse의 정의는 다음과 같습니다.data SnocList : (xs : List a) -> Type where
Empty : SnocList []
Snoc : (x : a) -> (xs : List a) -> (snoc : SnocList xs) -> SnocList (xs ++ [x])
여기서 Idris의 with 문법을 사용하면 helper 함수를 쓰지 않을 수 있습니다.snocList : (xs : List a) -> SnocList xs
그리고 뷰를 간단하게 설명했기 때문에 지금부터 형 드라이브 개발을 통해 임의의 (xs:Lista)를 SnocList xs의 전역 함수인 snocList로 바꾸어 보려고 합니다.형 구동 개발
TDD with Idris서에 따르면 형 구동 개발의 기본 단계는 다음과 같은 3가지다.
reverse : (lst : List a) -> List a
reverse lst = helper (snocList lst)
where
helper : SnocList xs -> List a
helper Empty = []
helper (Snoc x xs snoc) = x :: helper snoc
편집기 플러그인을 직접 사용하여 컴파일러가 대략적인 코드를 생성하도록 한다.reverse : (lst : List a) -> List a
reverse lst with (snocList lst)
reverse [] | Empty = []
reverse (xs ++ [x]) | (Snoc x xs snoc) = x :: reverse xs | snoc
편집기 플러그인을 사용하여 데이터 건설기를 따라 xs를 분할할 수 있습니다.snocList : (xs : List a) -> SnocList xs
이때의 시도 63?snocList_rhs_두 가지 유형은 이렇게 형성된 것이다.snocList : (xs : List a) -> SnocList xs
snocList xs = ?snocList_rhs
허선에서 현재 사용할 수 있는 변수와 그 유형, 다음에 만들어야 할 값이 가지고 있는 유형.스노크라이스트(x:xs)를 점선 위에 있는 것만 만드는 건 좀 어려울 것 같아.SnocList 자체는 데이터 구조자를 호출하는 형식이기 때문에 accumultator의 helper 함수를 정의하는 것이 좋습니다.
snocList : (xs : List a) -> SnocList xs
snocList [] = Empty
snocList (x :: xs) = let rec = snocList xs in ?snocList_rhs_2
여기서 helper가 xs=input++rest라는 것을 주의하면 이것은 리스트를 스캔하는 함수입니다. 이것은 accumulator와 함께 사용됩니다.input은 SnocList화가 완성된 부분List이며, rest는 향후 SnocList화가 남은 부분List를 표시한다.다음에 컴파일러로 하여금 helper의 프레임워크를 생성하게 합니다.(rest:Lista)를 SnocList로 변환하고 싶으므로 데이터 구조자에 따라 rest를 분해하십시오.
0 a : Type
x : a
xs : List a
rec : SnocList xs
------------------------------
snocList_rhs_2 : SnocList (x :: xs)
?helper_rhs_1형은 이렇다.snocList : (xs : List a) -> SnocList xs
snocList xs = helper Empty xs
where
helper : (acc : SnocList input) ->
(rest : List a) -> SnocList (input ++ rest)
acc에서 SnocList(input++[])를 얻을 수 있을 것 같지만 Idris는 당연히input++[]=input을 모릅니다.그래서 그렇다는 것을 증명해야 한다.
Data.List
snocList : (xs : List a) -> SnocList xs
snocList xs = helper Empty xs where
helper : (acc : SnocList input) ->
(rest : List a) -> SnocList (input ++ rest)
helper acc [] = ?helper_rhs_1
helper acc (x :: ys) = ?helper_rhs_2
이 함수가 증명했으니 이번에도 공부를 위해 그걸 하자.우선, 다음과 같이 보충한다. 0 a : Type
xs : List a
acc : SnocList input
------------------------------
helper_rhs_1 : SnocList (input ++ [])
Idris2에서는 정의에 사용된 implicit arguments가 명확하게 발표해야 하기 때문에 input을 발표하는 동시에 appeendNilRightNeutral의 유형 정의를 쓴다.이번에는 컴파일러가 appendNilRightNeutral의 골격을 생성하도록 합시다.그리고 유일한 매개 변수인 input을 분해합니다.appendNilRightNeutral : (l : List a) -> l ++ [] = l
?appendNilRightNeutral_rhs_한 사이즈는 이렇습니다.질의응답 없이 Refl입니다.다른 한편?appendNilRightNeutral_rhs_2예,
appendNilRightNeutral : (input : List a) -> input ++ [] = input
snocList : (xs : List a) -> SnocList xs
snocList xs = helper Empty xs where
helper : {input : List a} ->
(acc : SnocList input) ->
(rest : List a) -> SnocList (input ++ rest)
helper {input} acc [] = ?helper_rhs_1
helper acc (x :: ys) = ?helper_rhs_2
.좀 복잡해 보이는데 xs 적용 귀납법에 관해서는 됩니다.대부분의 증명은 구조에 관한 귀납법이다.
이번에는 어때?xs에 귀속적으로 적용하면 모델이 바뀐다.
appendNilRightNeutral : (input : List a) -> input ++ [] = input
appendNilRightNeutral [] = ?appendNilRightNeutral_rhs_1
appendNilRightNeutral (x :: xs) = ?appendNilRightNeutral_rhs_2
snocList : (xs : List a) -> SnocList xs
snocList xs = helper Empty xs where
helper : {input : List a} ->
(acc : SnocList input) ->
(rest : List a) -> SnocList (input ++ rest)
helper {input} acc [] = appendNilRightNeutral input
helper acc (x :: ys) = ?helper_rhs_2
현재,rec의 유형 rhs만약 2의 왼쪽을 다시 쓸 수 있다면 x:xs=x:xs, 기쁘고 축하할 만한 Refl.다시 쓰는 문법이 있고, rewrite Ain B를 쓰면 A의 형식으로 B를 다시 쓸 수 있다. 0 a : Type
------------------------------
appendNilRightNeutral_rhs_1 : [] = []
그리고 0 a : Type
x : a
xs : List a
------------------------------
appendNilRightNeutral_rhs_2 : x :: (xs ++ []) = x :: xs
저는 이웃입니다. 기쁘고 축하합니다.이제 증명 끝났어.appendNilRightNeutral : (input : List a) -> input ++ [] = input
appendNilRightNeutral [] = Refl
appendNilRightNeutral (x :: xs)
= let rec = appendNilRightNeutral xs in ?rhs_2
?helper_rhs_1 의 유형은 0 a : Type
x : a
xs : List a
rec : xs ++ [] = xs
------------------------------
rhs_2 : x :: (xs ++ []) = x :: xs
이니까 리트리트로 다시 쓰면 이 홀이 끝이야.appendNilRightNeutral : (input : List a) -> input ++ [] = input
appendNilRightNeutral [] = Refl
appendNilRightNeutral (x :: xs)
= let rec = appendNilRightNeutral xs in rewrite rec in ?rhs
나머지는 helperrhs_먼저 모델을 봅시다. 0 a : Type
x : a
xs : List a
rec : xs ++ [] = xs
------------------------------
rhs : x :: xs = x :: xs
쳐다보면 보이는데, SnocList(input++(y:ys) 이런 유형은SnocList(input++[y])++ys)형과 같고 Helper(Snocy input acc)ys를 호출할 때의 결과형과 같습니다.
따라서 지금 input++(y:ys)를 (input++[y])++ys로 바꿀 수 있다면 이hole도 채울 수 있습니다.(y:ys)=[y]++ys를 이용하여
(input++(y:ys)=(input++([y]++ys)=(input+++[y])++ys)만 증명하면 됩니다.
이것은 단지 appeend의 결합율, Data를 나타낸다.리스트에서는 그게 맞아요.
appendAssociative : (l, c, r : List a) -> l++ (c++ r) = (l++ c)++ r
이런 함수가 있다.이것도 아까와 마찬가지로 다음과 같다.
appendNilRightNeutral : (input : List a) -> input ++ [] = input
appendNilRightNeutral [] = Refl
appendNilRightNeutral (x :: xs) = rewrite appendNilRightNeutral xs in Refl
snocList : (xs : List a) -> SnocList xs
snocList xs = helper Empty xs where
helper : {input : List a} ->
(acc : SnocList input) ->
(rest : List a) -> SnocList (input ++ rest)
helper {input} acc [] = ?helper_rhs_1
helper acc (x :: ys) = ?helper_rhs_2
이때, 0 a : Type
xs : List a
input : List a
acc : SnocList input
------------------------------
helper_rhs_1 : SnocList (input ++ [])
,appendNilRightNeutral : (input : List a) -> input ++ [] = input
appendNilRightNeutral [] = Refl
appendNilRightNeutral (x :: xs) = rewrite appendNilRightNeutral xs in Refl
snocList : (xs : List a) -> SnocList xs
snocList xs = helper Empty xs where
helper : {input : List a} ->
(acc : SnocList input) ->
(rest : List a) -> SnocList (input ++ rest)
helper {input} acc [] = rewrite appendNilRightNeutral input in acc
helper acc (y :: ys) = ?helper_rhs_2
, rewrite를 사용하여 덮어쓰기 0 a : Type
xs : List a
y : a
ys : List a
acc : SnocList input
------------------------------
helper_rhs_2 : SnocList (input ++ (y :: ys))
.이번 시도?helper_rhs_2 의 유형은appendAssociative : (l, c, r : List a) -> l ++ (c ++ r) = (l ++ c) ++ r
appendAssociative [] c r = Refl
appendAssociative (x :: xs) c r = rewrite appendAssociative xs c r in Refl
, helper(Snocy input acc)ys:SnocList((input++[y])++ys)인 경우 최종snocList : (xs : List a) -> SnocList xs
snocList xs = helper Empty xs where
helper : {input : List a} ->
(acc : SnocList input) ->
(rest : List a) -> SnocList (input ++ rest)
helper {input} acc [] = rewrite appendNilRightNeutral input in acc
helper {input} acc (y :: ys) =
let thm = appendAssociative input [y] ys in ?helper_rhs_2
.지금까지 snocList의 정의였습니다.
Reference
이 문제에 관하여(SnocList recursive view 형 드라이버를 개발해 보세요 in Idris2), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/hiropon21/articles/d9331813644265텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)