Контрастирование дженериков C# с Haskell параметризовало типы

Вызов jest.mock в тесте не работает .

Вам нужно вывести макет за пределы теста и убедиться, что ваша заводская функция не имеет внешних зависимостей.

Примерно так:

import { View } from 'react-native';
import React from 'react';
import { shallow } from 'enzyme';
import connect from '../connect.js';
import LanguageProvider from '../LanguageProvider';
import LanguageStore from '../LanguageStore';

jest.mock('../LanguageStore', () => {
  const language = "en"
  const stringsMock = {
    setLanguage: jest.fn()
  };
  const mockSetLanguage = jest.fn();

  return () => ({
    language,
    strings: stringsMock,
    setLanguage: mockSetLanguage,
  })
});

it('renders correctly', () => {
  const TestComponent = connect(Test);
  const strings = { test: 'Test' };
  const wrapper = shallow();
  expect(wrapper.get(0)).toMatchSnapshot();
});


class Test extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return ;
  }
}

21
задан Don Stewart 20 April 2011 в 04:53
поделиться

4 ответа

Вот одно различие для учета:

C# имеет выделение подтипов, но Haskell не делает, что означает, с одной стороны, что Вы знаете больше вещей путем простого рассмотрения типа Haskell.

id :: a -> a

Эта функция Haskell принимает значение типа и возвращает то же самое значение того же самого типа. Если Вы даете ему a Bool, это возвратит a Bool. Дайте ему a Int, это возвратит a Int. Дайте ему a Person, это возвратит a Person.

В C# Вы не можете быть так уверены. Это - та 'функция' в C#:

public T Id<T>(T x);

Теперь, из-за выделения подтипов в Вас мог назвать его как так:

var pers = Id<Person>(new Student());

В то время как pers имеет тип Person, аргумент Id функция не.Действительно? pers мог бы иметь более определенный тип, чем просто Person. Person мог даже быть абстрактный тип, гарантировав это pers будет иметь более определенный тип.

Как Вы видите, даже с функцией, столь же простой как id система типов.NET уже допускает намного больше, чем более строгая система типов от Haskell. В то время как это могло бы быть полезно, чтобы сделать некоторую работу программирования, она также мешает рассуждать о программе, просто смотря типы вещей (который является радостью, чтобы сделать в Haskell).


И вторая вещь, существует специальный полиморфизм (иначе перегружающийся) в Haskell, с помощью механизма, известного как 'классы типа'.

equals :: Eq a => a -> a -> Bool

Эта функция проверяет, равны ли два значения. Но не только любые два значения, просто значения, которые имеют экземпляры для Eq класс. Это - вид подобных ограничений на параметры типа в C#:

public bool Equals<T>(T x, T y) where T : IComparable

Существует различие, как бы то ни было. С одной стороны, выделение подтипов: Вы могли инстанцировать его с Person и назовите его с Student и Teacher.

Но существует также различие в том, во что это компилирует. Код C# компилирует в почти точно, что говорит его тип. Средство проверки типа удостоверяется, что аргументы реализуют надлежащий интерфейс, и, чем Вы хороши.

Принимая во внимание, что код Haskell соответствует чему-то вроде этого:

equals :: EqDict -> a -> a -> Bool

Функция получает дополнительный аргумент, словарь всех функций, которые она должна сделать Eq вещи. Вот то, как Вы могли использовать эту функцию, и во что она компилирует:

b1 = equals 2 4          --> b1 = equals intEqFunctions 2 4
b2 = equals True False   --> b2 = equals boolEqFunctions True False

Это также показывает то, что делает выделение подтипов в такой боли, вообразите если это, если это возможно.

b3 = equals someStudent someTeacher
     --> b3 = equals personEqFunctions someStudent someTeacher

Как personEqFunctions словарь, который, как предполагают, выяснял, если a Student равно a Teacher? У них даже нет тех же полей.

Короче говоря, в то время как ограничения типа Haskell на первый взгляд могли бы быть похожими на ограничения типа.NET, они реализованы полностью по-другому и компилируют в две действительно разных вещи.

31
ответ дан 29 November 2019 в 06:35
поделиться

Мы можем сделать другие вещи с классами типа Haskell слишком теперь. Поиск с помощью Google для "дженериков" в Haskell открывает целое поле более высокого разряда полиморфное универсальное программирование вне стандартного параметрического полиморфизма, о котором большинство людей думает как "дженерики".

Например, GHC недавно получил семейства шрифтов, включив все виды интересных возможностей программирования типа. Очень простым примером являются решения представления данных на тип для произвольных полиморфных контейнеров.

Я могу сделать класс для, говорят, списки,

class Listy a where

    data List a 
             -- this allows me to write a specific representation type for every particular 'a' I might store!

    empty   :: List a
    cons    :: a -> List a -> List a
    head    :: List a -> a
    tail    :: List a -> List a

Я могу записать функции, которые воздействуют на что-либо, что инстанцирует Списка:

map :: (Listy a, Listy b) => (a -> b) -> List a -> List b
map f as = go as
  where
    go xs
        | null xs   = empty
        | otherwise = f (head xs) `cons` go (tail xs)

И все же мы никогда не давали конкретный тип представления.

Теперь, когда класс для универсального списка. Я могу дать особые хитрые представления на основе типов элемента. Так, например, для списков Интервала, я мог бы использовать массив:

instance Listy Int where

data List Int = UArray Int Int

...

Таким образом, можно начать делать некоторое довольно мощное универсальное программирование.

18
ответ дан 29 November 2019 в 06:35
поделиться

В продолжение «вы можете столкнуться с большими проблемами, думая, что концепция, с которой вы знакомы на одном языке, совпадает с другим языком [в котором вы новичок]» часть этого вопроса:

Вот ключевое отличие (скажем, от Ruby), которое вы должны понимать, когда используете классы типов Haskell. Для такой функции, как

add :: Num a => a -> a -> a
add x y = x + y

. Это не означает, что x и y оба являются любыми типами класса Num . Это означает, что x и y относятся к одному и тому же типу, который относится к классу Num . «Ну, конечно, вы говорите; a то же самое, что a ». Что я тоже говорю, но мне потребовалось много месяцев, чтобы перестать думать, что если бы x было Int , а y было Integer , это было бы как добавление Fixnum и Bignum в Ruby. Скорее:

*Main> add (2::Int) (3::Integer)

<interactive>:1:14:
    Couldn't match expected type `Int' against inferred type `Integer'
    In the second argument of `add', namely `(3 :: Integer)'
    In the expression: add (2 :: Int) (3 :: Integer)
    In the definition of `it': it = add (2 :: Int) (3 :: Integer)

Другими словами, подклассы (хотя оба экземпляра Num , конечно, также являются экземплярами Eq ) и утиная типизация исчезли, детка.

Звучит красиво. простой и очевидный, но требуется некоторое время, чтобы научиться понимать это инстинктивно, а не просто интеллектуально, по крайней мере, если вы пришли из многолетнего опыта Java и Ruby.

И нет, как только я овладею этим , Я немного не скучаю по подклассам. (Ну, может быть, время от времени немного, но я приобрел гораздо больше, чем потерял. И когда я действительно скучаю по этому,

6
ответ дан 29 November 2019 в 06:35
поделиться

Еще одно большое отличие состоит в том, что универсальные шаблоны C # не допускают абстракции над конструкторами типов (т.е. видами, отличными от *), в то время как Haskell это делает. Попробуйте перевести следующий тип данных в класс C #:

newtype Fix f = In { out :: f (Fix f) }
7
ответ дан 29 November 2019 в 06:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: