내가 겪고있는 학습 문제에서 적용, 작성 등의 작업을 수행하는 함수에 대한 typeclass가 필요하다는 것을 깨달았습니다.
함수의 표현을 함수 자체처럼 취급하는 것이 편리하므로 함수를 암시 적으로 해석하는 인터프리터를 사용하고 함수를 작성하면 새로운 설명이 도출됩니다.
함수에 대한 유형 클래스가 있으면 특수한 종류의 함수에 대한 유형 클래스를 파생시킬 수 있습니다. 필자의 경우에는 뒤집을 수없는 함수가 필요합니다.
예를 들어 정수 오프셋을 적용하는 함수는 정수를 포함하는 ADT로 나타낼 수 있습니다. 이러한 함수를 적용한다는 것은 정수를 추가하는 것을 의미합니다. 랩핑 된 정수를 추가하여 구성이 구현됩니다. 역함수는 정수를 부정합니다. identity 함수는 0을 래핑합니다. 상수 함수는 적절한 표현이 없기 때문에 제공 할 수 없습니다.
물론 값이 Haskell의 진정한 기능인 것처럼 철자를 쓸 필요는 없지만 일단 아이디어를 얻은 후에는 이와 같은 라이브러리가 이미 존재하고 표준 철자를 사용한다고 생각했습니다. 그러나 Haskell 라이브러리에서 이러한 유형 클래스를 찾을 수 없습니다.
Data.Function 모듈을 찾았 지만 typeclass 가 없습니다. Prelude에서도 사용할 수있는 몇 가지 일반적인 함수 만 있습니다.
그렇다면 함수형 클래스가없는 이유는 무엇입니까? "그렇지 않아서"또는 "생각이 그렇게 유용하지 않기 때문에"입니까? 아니면 아이디어에 근본적인 문제가 있습니까?
지금까지 내가 생각한 가장 큰 문제는 루핑 문제를 피하기 위해 실제 함수의 함수 응용 프로그램이 컴파일러에 의해 특수 사례되어야한다는 것입니다.이 함수를 적용하려면 함수 응용 프로그램 함수를 적용해야합니다. 그렇게하려면 함수 응용 프로그램 함수를 호출해야합니다.
더 많은 단서
내가 목표로하는 것을 보여주는 예제 코드 ...
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
-- In my first version, Doable only had the one argument f. This version
-- seemed to be needed to support the UndoableOffset type.
--
-- It seems to work, but it also seems strange. In particular,
-- the composition function - a and b are in the class, but c isn't,
-- yet there's nothing special about c compared with a and b.
class Doable f a b where
fwdApply :: f a b -> a -> b
compDoable :: f b c -> f a b -> f a c
-- In the first version, I only needed a constraint for
-- Doable f a b, but either version makes sense.
class (Doable f a b, Doable f b a) => Undoable f a b where
bwd :: f a b -> f b a
bwdApply :: f a b -> b -> a
bwdApply f b = fwdApply (bwd f) b
-- Original ADT - just making sure I could wrap a pair of functions
-- and there were no really daft mistakes.
data UndoableFn a b = UFN { getFwd :: a -> b, getBwd :: b -> a }
instance Doable UndoableFn a b where
fwdApply = getFwd
compDoable f g = UFN ((getFwd f) . (getFwd g)) ((getBwd g) . (getBwd f))
instance Undoable UndoableFn a b where
bwd f = UFN (getBwd f) (getFwd f)
bwdApply = getBwd
-- Making this one work led to all the extensions. This representation
-- can only represent certain functions. I seem to need the typeclass
-- arguments, but also to need to restrict which cases can happen, hence
-- the GADT. A GADT with only one constructor still seems odd. Perhaps
-- surprisingly, this type isn't just a toy (except that the whole thing's
-- a toy really) - it's one real case I need for the exercise. Still a
-- simple special case though.
data UndoableOffset a b where
UOFF :: Int -> UndoableOffset Int Int
instance Doable UndoableOffset Int Int where
fwdApply (UOFF x) y = y+x
compDoable (UOFF x) (UOFF y) = UOFF (x+y)
instance Undoable UndoableOffset Int Int where
bwdApply (UOFF x) y = y-x
bwd (UOFF x) = UOFF (-x)
-- Some value-constructing functions
-- (-x) isn't shorthand for subtraction - whoops.
undoableAdd :: Int -> UndoableFn Int Int
undoableAdd x = UFN (+x) (\y -> y-x)
undoableMul :: Int -> UndoableFn Int Int
undoableMul x = UFN (*x) (`div` x)
-- With UndoableFn, it's possible to define an invertible function
-- that isn't invertible - to break the laws. To prevent that, need
-- the UFN constructor to be private (and all public ops to preserve
-- the laws). undoableMul is already not always invertible.
validate :: Undoable f a b => Eq a => f a b -> a -> Bool
validate f x = (bwdApply f (fwdApply f x)) == x
-- Validating a multiply-by-zero invertible function shows the flaw
-- in the validate-function plan. Must try harder.
main = do putStrLn . show $ validate (undoableAdd 3) 5
putStrLn . show $ validate (undoableMul 3) 5
--putStrLn . show $ validate (undoableMul 0) 5
fb1 <- return $ UOFF 5
fb2 <- return $ UOFF 7
fb3 <- return $ compDoable fb1 fb2
putStrLn $ "fwdApply fb1 3 = " ++ (show $ fwdApply fb1 3)
putStrLn $ "bwdApply fb1 8 = " ++ (show $ bwdApply fb1 8)
putStrLn $ "fwdApply fb3 2 = " ++ (show $ fwdApply fb3 2)
putStrLn $ "bwdApply fb3 14 = " ++ (show $ bwdApply fb3 14)
이 응용 프로그램에는 통합 값이 같지 않은 프롤로그 스타일 논리가 a = f(b)
아닌 제약 조건 과 같은 불가역 함수를 통해 관련되는 일종의 통일이 포함됩니다 a = b
. 구성의 대부분은 노조 찾기 구조를 최적화하여 생성됩니다. 역수의 필요성은 분명해야합니다.
통합 집합의 항목에 정확한 값이없는 경우 해당 통합 집합의 다른 항목에 대해서만 특정 항목을 수량화 할 수 있습니다. 이것이 바로 "실제"기능을 사용하고 싶지 않은 이유입니다. 나는 전체 기능 측면을 떨어 뜨릴 수 있고 절대적이고 상대적인 양을 가질 수 있습니다. 아마도 숫자 / 벡터 만 필요할 수도 있습니다. (+)
그러나 내 내부 건축 우주 비행사는 그의 재미를 원합니다.
링크를 다시 분리하는 유일한 방법은 역 추적을 통하는 것이며 모든 것이 순수합니다. 조합 찾기는 키를 IntMap
"포인터"로 사용하여 수행됩니다 . 나는 단순한 노동 조합 찾기 작업을했지만 아직 뒤집을 수없는 기능을 추가하지 않았으므로 여기에 열거 할 요점이 없습니다.
Applicative, Monad, Arrow 등을 사용할 수없는 이유
내가 제공하는 함수 추상화 클래스가 필요한 주요 작업은 응용 프로그램 및 구성입니다. 친숙하게 들립니다. 예를 들어 Applicative
(<*>)
, Monad
(>>=)
그리고 Arrow
(>>>)
모든 컴포지션 기능입니다. 그러나 필자의 경우 함수 추상화를 구현하는 형식에는 함수를 나타내지 만 함수를 포함 할 수 없으며 포함 할 수없는 일부 데이터 구조가 포함되어 있으며 제한된 함수 집합 만 나타낼 수 있습니다.
코드 설명에서 언급했듯이 "통합"클러스터의 항목에 정확한 값이 없기 때문에 한 항목을 다른 항목에 대해서만 수량화 할 수 있습니다. 나는 그 함수의 표현을 이끌어 내고자한다. 일반적으로 제공된 여러 함수 (조합 / 찾기 트리에서 공통 조상까지 걸어 가기)와 여러 역함수 (다른 것으로 내려 가기)로 구성 될 것이다. 안건).
간단한 경우-원래의 "함수"가 정수 오프셋 "함수"로 제한되는 경우 정수 오프셋 "함수"로 구성된 결과를 원합니다-구성 요소 오프셋을 추가하십시오. 이것이 컴포지션 함수가 응용 프로그램 함수뿐만 아니라 클래스에 있어야하는 이유의 큰 부분입니다.
이 방법은 내가 작업을 제공 할 수없는 pure
, return
또는 arr
내 유형, 내가 사용할 수 있도록 Applicative
, Monad
또는 Arrow
.
이것은 이러한 유형의 실패가 아니며 추상화의 불일치입니다. 내가 원하는 추상화는 단순한 순수한 기능입니다. 예를 들어 부작용이 없으며 모든 기능에 적용되는 표준 (.)과 다른 기능을 시퀀싱하고 구성하기위한 편리한 표기법을 작성할 필요가 없습니다.
나는 인스턴스 할 수Category
있습니다. 나는 필요하지는 않지만 모든 기능적인 것들이 정체성을 제공 할 수 있다고 확신합니다. 그러나 Category
응용 프로그램을 지원하지 않기 때문에 여전히 해당 작업을 추가하려면 파생 클래스가 필요합니다.
Applicative
옳지 않다고 생각 합니다-함수뿐만 아니라 값도 줄 바꿈해야하지만 함수 만 줄 바꿈하고 감싸 인 함수는 실제로 함수이지만 랩 된 함수는 일반적으로 (in 가장 일반적인 경우는 기능을 설명하는 AST입니다). 어디 <*>
유형이 f (a -> b) -> f a -> f b
나는 유형의 응용 프로그램 운영자 원하는 및 도메인을 지정하고 포장 기능의 공역을,하지만 래퍼 안에 것은 없습니다 (필요) 진정한 기능입니다. 애로 우즈 (Arrows)-아마도, 내가 볼 것이다. g a b -> a -> b
a
b