카테고리 보관물: Software

Software

함수에 대한 타입 클래스가없는 이유는 무엇입니까? = getFwd compDoable f g

내가 겪고있는 학습 문제에서 적용, 작성 등의 작업을 수행하는 함수에 대한 typeclass가 필요하다는 것을 깨달았습니다.

  1. 함수의 표현을 함수 자체처럼 취급하는 것이 편리하므로 함수를 암시 적으로 해석하는 인터프리터를 사용하고 함수를 작성하면 새로운 설명이 도출됩니다.

  2. 함수에 대한 유형 클래스가 있으면 특수한 종류의 함수에 대한 유형 클래스를 파생시킬 수 있습니다. 필자의 경우에는 뒤집을 수없는 함수가 필요합니다.

예를 들어 정수 오프셋을 적용하는 함수는 정수를 포함하는 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응용 프로그램을 지원하지 않기 때문에 여전히 해당 작업을 추가하려면 파생 클래스가 필요합니다.



답변

글쎄, 나는 “함수 -y”를 나타내는 것으로 스스로 시장에 내놓아 진 아이디어에 대해 잘 모른다. 그러나 가까이 오는 몇 가지가 있습니다

카테고리

정체성과 구성이있는 간단한 기능 개념이 있다면 범주보다 있습니다.

class Category c where
  id :: c a a
  (.) :: c b c -> c a b -> c a c

단점은 당신이 개체의 집합 멋진 카테고리의 인스턴스를 만들 수 있다는 것입니다 ( a, b, 및 c). 내가 생각하는 맞춤 카테고리 클래스를 만들 수 있습니다.

화살표

함수에 제품 개념이 있고 임의의 함수를 삽입 할 수있는 경우 화살표가 사용자를위한 것보다

 class Arrow a where
   arr :: (b -> c) -> a b c
   first :: a b c -> a (b, d) (c, d)
   second :: a b c -> a (d, b) (d, c)

ArrowApply 원하는 것에 중요한 응용 프로그램 개념이 있습니다.

응용

응용 프로그램은 응용 프로그램에 대한 개념을 가지고 있으며, AST에서 함수 응용 프로그램을 나타내는 데 사용했습니다.

class Functor f => Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f b -> f c

다른 많은 아이디어가 있습니다. 그러나 일반적인 주제는 함수를 나타내는 일부 데이터 구조를 작성하여 해석 함수에 전달하는 것입니다.

이것은 또한 얼마나 많은 무료 모나드가 작동하는지입니다. 나는 당신이 용감하다고 느끼면 이것들을 찌를 것을 제안 할 것입니다, 그들은 당신이 제안하는 것들을위한 강력한 도구이며, do표기법을 사용하여 데이터 구조를 구축 한 다음 다른 기능으로 계산에 영향을 미치는 측면으로 축소 할 수 있습니다 . 그러나 이러한 기능은 데이터 구조에서만 작동하며 실제로 어떻게 만들 었는지 알지 못한다는 것이 장점입니다. 이것이 당신의 통역사에 대한 제안입니다.


답변

당신이 지적했듯이, 여기서 Applicative를 사용할 때의 주요 문제는에 대한 합리적인 정의가 없다는 것입니다 pure. 따라서 Apply발명되었다. 적어도 내 이해입니다.

불행히도, 나는 Apply그 인스턴스가 아닌 예제를 가지고 있지 않습니다 Applicative. 이것이 사실이라고 주장 IntMap하지만 이유를 모르겠습니다. 마찬가지로, 예제-오프셋 정수- Apply인스턴스를 허용하는지 여부를 모르겠습니다 .


답변

언급 이외에 Category, ArrowApplicative:

Data.LambdaConal Elliott 도 발견 했습니다.

람다와 같은 구성을 가진 일부 함수와 유사한 클래스

물론 흥미로워 보이지만 예제없이 이해하기는 어렵습니다 …

위키 페이지 에서 라이브러리 생성을 유발 한 것 중 하나 인 유형 가치 (TV) 에 대한 예를 찾을 수 있습니다 TypeCompose. 입력 및 함수 값 출력을 참조하십시오 .

TV 라이브러리의 아이디어는 하스켈 값 (함수 포함)을 확실한 방식으로 표시하는 것입니다.

베어 론크를 게시하지 않는 것에 대한 StackOverflow 규칙을 따르기 위해 아래에 약간의 비트를 복사하여 다음과 같은 아이디어를 제공합니다.

첫 번째 예는 다음과 같습니다.

apples, bananas :: CInput Int
apples  = iTitle "apples"  defaultIn
bananas = iTitle "bananas" defaultIn

shoppingO :: COutput (Int -> Int -> Int)
shoppingO = oTitle "shopping list" $
            oLambda apples (oLambda bananas total)

shopping :: CTV (Int -> Int -> Int)
shopping = tv shoppingO (+)

다음과 같이 실행될 때 제공됩니다 runIO shopping(더 많은 주석, GUI 및 더 많은 예제는 여기 참조).

shopping list: apples: 8
bananas: 5
total: 13

답변